37

我经常以交互方式循环例如我的文件并希望对所有文件执行特定操作,假设我想重命名所有文件:

for file in $(ls); do mv "$file" "${file}_new"; done

这工作正常。但是在调用这个命令之前,我想看看它实际上做了什么,所以我会在前面添加一个 echo

for file in $(ls); do echo mv "$file" "${file}_new"; done

然后它会向我显示它会调用的所有命令。如果我对它们感到满意,我会删除echo并执行它。

但是,当命令更微妙时,可能包括管道或多个命令,这不再起作用。当然我可以使用'这样特殊字符不会被解释,但是我没有参数扩展。我也可以转义特殊字符,但这会变得非常乏味。

我的问题是,最好的方法是什么?我已经阅读了man bash有关选项的信息-n,它执行“读取命令但不执行它们。这可用于检查 shell 脚本的语法错误。交互式 shell 会忽略它。” 这正是我所需要的,但我需要它用于交互式外壳。请注意,选项-x-v没有帮助,因为它不仅会显示命令,还会调用它,然后可能已经太晚了。

4

4 回答 4

31

正如devnull所解释的,没有“试运行”选项,但有一个简单的解决方法:

debug=
#debug=echo

$debug mv "$file" "${file}_new"

如果您从第二个分配中删除注释(不更改任何其他内容),则为危险mv命令启用“试运行”。

更复杂的方法是检查一些条件(如命令行选项):

debug=
if [[ ...enable dry run?... ]]; then
    debug=echo
fi

注意:只有当您-u启用了选项(“替换时将未设置的变量视为错误。”)时,才需要空赋值。

重要提示:当您的命令使用重定向时,这将无法正常工作(因为 shell 将始终在命令启动之前执行它们)。

于 2013-10-01T15:22:45.703 回答
29

这个线程会告诉你为什么永远不会为bash.

请参阅Eric Blake的回复:

>我的问题是为什么不能提供或提供这样的选择,

稍加思考就会说明为什么这永远不会实施。这样的选项会输出以下内容:

if complex_command; then
  foo=command1
else
  foo=command2
fi
$foo args

在. $foo args_ $foo_ complex_command因此,没有运行事物就无法预演最终的结果,但运行事物与预演的目标背道而驰。

也就是说,您可能对该项目感兴趣,该bashdb项目使用 bash 钩子提供调试器界面,您可以在其中单步执行 bash 脚本;这与告诉您脚本会做什么不同,但它至少可以让您控制实际运行的脚本的多少。

于 2013-10-01T12:23:44.977 回答
10

有一个github包叫做maybe,这里有一个例子:

$ maybe rm file
> maybe has prevented rm file from performing 1 file system operations:
>
> delete /home/user/file
>
> Do you want to rerun rm file and permit these operations? [y/N]
于 2016-02-19T03:13:51.600 回答
2

实际上,您可以在脚本中执行此操作

添加:

set -x # Print commands and their arguments as they are executed.
set -n # Read commands but do not execute them

在脚本的开头

一个好的做法是set -e在错误时添加退出

(更多参考人集

于 2019-03-18T11:41:00.087 回答