107

您可以在运行时编辑 shell 脚本并让更改影响正在运行的脚本吗?

我对 csh 脚本的具体情况很好奇,我有该批处理运行一堆不同的构建风格并运行一整夜。如果我在操作中遇到什么问题,我想进去添加额外的命令,或者注释掉未执行的命令。

如果不可能,是否有任何外壳或批处理机制可以让我这样做?

当然我已经尝试过了,但要等几个小时才能看到它是否有效,我很好奇幕后发生了什么或没有发生什么。

4

11 回答 11

58

确实会影响,至少在我的环境中是 bash,但是以非常不愉快的方式。请参阅这些代码。首先a.sh

#!/bin/sh

echo "First echo"
read y

echo "$y"

echo "That's all."

b.sh

#!/bin/sh

echo "First echo"
read y

echo "Inserted"

echo "$y"

# echo "That's all."

$ cp a.sh run.sh
$ ./run.sh
$ # open another terminal
$ cp b.sh run.sh  # while 'read' is in effect
$ # Then type "hello."

就我而言,输出始终是:

你好
你好
就这样。
就这样。

(当然,自动化要好得多,但上面的例子是可读的。)

[编辑] 这是不可预测的,因此很危险。最好的解决方法是 ,如此处所述, 将所有内容放在一个大括号中,并在右大括号之前放置 "exit"仔细阅读链接的答案以避免陷阱。

[添加] 确切的行为取决于一个额外的换行符,可能还取决于您的 Unix 风格、文件系统等。如果您只是想查看一些影响,只需在 b.sh 之前和/或之后添加“echo foo/bar” “阅读”行。

于 2011-06-10T07:44:57.097 回答
48

试试这个...创建一个名为bash-is-odd.sh

#!/bin/bash
echo "echo yes i do odd things" >> bash-is-odd.sh

这表明 bash 确实是在“随时”解释脚本。事实上,编辑一个长时间运行的脚本会产生不可预知的结果,插入随机字符等。为什么?因为 bash 从最后一个字节位置读取,所以编辑会移动正在读取的当前字符的位置。

总之,由于这个“特性”,Bash 非常非常不安全。svn 和rsync与 bash 脚本一起使用时特别麻烦,因为默认情况下它们“合并”结果......就地编辑。rsync有一种模式可以解决这个问题。svn 和 git 没有。

我提出一个解决方案。创建一个名为/bin/bashx

#!/bin/bash
source "$1"

现在#!/bin/bashx在您的脚本上使用并始终使用bashx而不是bash. 这解决了问题 - 您可以安全地rsync编写脚本。

@AF7 提出/测试的替代(在线)解决方案:

{
   # your script
exit $?
} 

花括号防止编辑,退出防止追加。当然,如果 bash 带有一个选项,例如-w(整个文件)或其他类似的选项,我们都会变得更好。

于 2013-10-17T15:28:53.537 回答
18

将您的脚本分解为函数,每次调用一个函数时,您source都会从一个单独的文件中调用它。然后,您可以随时编辑文件,并且您的运行脚本将在下次获取源时获取更改。

foo() {
  source foo.sh
}
foo
于 2010-08-03T18:59:03.933 回答
3

好问题!希望这个简单的脚本有所帮助

#!/bin/sh
echo "Waiting..."
echo "echo \"Success! Edits to a .sh while it executes do affect the executing script! I added this line to myself during execution\"  " >> ${0}
sleep 5
echo "When I was run, this was the last line"

在 linux 下,对执行中的 .sh 所做的更改似乎是由执行脚本制定的,如果你可以输入足够快的话!

于 2018-09-06T04:24:38.767 回答
2

我没有安装 csh,但是

#!/bin/sh
echo Waiting...
sleep 60
echo Change didn't happen

运行那个,快速编辑最后一行阅读

echo Change happened

输出是

Waiting...
/home/dave/tmp/change.sh: 4: Syntax error: Unterminated quoted string

哼。

我猜对 shell 脚本的编辑在重新运行之前不会生效。

于 2010-08-03T15:57:08.500 回答
2

一个有趣的旁注 - 如果您正在运行 Python 脚本,它不会改变。(对于任何了解 shell 如何运行 Python 脚本的人来说,这可能是显而易见的,但认为这对于寻找此功能的人来说可能是一个有用的提醒。)

我建立:

#!/usr/bin/env python3
import time
print('Starts')
time.sleep(10)
print('Finishes unchanged')

然后在另一个 shell 中,当它处于睡眠状态时,编辑最后一行。完成后,它会显示未更改的行,大概是因为它正在运行.pyc? 同样的情况发生在 Ubuntu 和 macOS 上。

于 2018-11-09T14:04:57.093 回答
1

如果这一切都在一个脚本中,那么它不会起作用。但是,如果您将其设置为调用子脚本的驱动程序脚本,那么您可能能够在调用子脚本之前更改子脚本,或者如果您正在循环,则在再次调用它之前更改子脚本,在这种情况下,我相信这些更改将反映在执行中。

于 2010-08-03T16:10:00.873 回答
1

使用 Zsh 代替您的脚本。

AFAICT,Zsh 没有表现出这种令人沮丧的行为。

于 2020-03-31T23:53:19.647 回答
0

我没有听到......但是如果有一些间接的话:

BatchRunner.sh

Command1.sh
Command2.sh

命令1.sh

runSomething

命令2.sh

runSomethingElse

那么您应该能够在 BatchRunner 正确之前编辑每个命令文件的内容吗?

或者

更简洁的版本会让 BatchRunner 查看单个文件,在该文件中它会一次连续运行一行。那么您应该能够在第一个文件运行时编辑第二个文件吗?

于 2010-08-03T16:05:22.383 回答
-5

通常,在运行时编辑脚本并不常见。您所要做的就是对您的操作进行控制检查。使用 if/else 语句检查条件。如果某件事失败了,那么就这样做,否则就那样做。这就是要走的路。

于 2010-08-03T15:57:30.247 回答
-86

脚本不是这样工作的;执行副本独立于您正在编辑的源文件。下次运行脚本时,它将基于最近保存的源文件版本。

将此脚本分解为多个文件并单独运行它们可能是明智的。这将减少执行失败的时间。(即,将批处理拆分为一个构建风格脚本,分别运行每个脚本以查看哪个导致了问题)。

于 2010-08-03T15:54:28.787 回答