是否可以通过回显命令来运行Shell脚本,但实际上不执行这些命令?
假设我有脚本删除名称存储在变量中的文件:
#!/bin/bash
set -v
FN="filename"
rm -f ${FN}
添加set -v将在执行前回显以下命令:
$ ./scr.sh
FN="filename"
rm -f ${FN}
现在,我想看看没有实际删除文件的该脚本的流程。IOW,我想防止对外部环境和文件系统的任何影响。这可能吗?
我可以用命令包装所有命令echo,但冗长的脚本很累人。
是否可以通过回显命令来运行Shell脚本,但实际上不执行这些命令?
假设我有脚本删除名称存储在变量中的文件:
#!/bin/bash
set -v
FN="filename"
rm -f ${FN}
添加set -v将在执行前回显以下命令:
$ ./scr.sh
FN="filename"
rm -f ${FN}
现在,我想看看没有实际删除文件的该脚本的流程。IOW,我想防止对外部环境和文件系统的任何影响。这可能吗?
我可以用命令包装所有命令echo,但冗长的脚本很累人。
Answers:
如果没有实际执行脚本,就无法单步执行脚本以查看其执行方式。在您的示例中,没有if语句或循环。但是在实际的脚本中,通常会有很多条件语句。将采用哪个分支通常取决于外壳程序运行前一个命令时发生的情况。如果它不运行该命令,则外壳程序将无法知道它将产生什么输出或返回代码是什么,下一个条件分支或赋值语句可能依赖于该输出。
如果重点是您想仔细检查一个脚本并在运行之前知道它的功能,那不是一个坏主意。但实际上,实现此目标的最佳方法是仅使用less或vi或类似方式浏览文件。
添加
如果您正在开发脚本,并且想在第一时间完成脚本,测试逻辑但如果遇到错误则不做任何破坏,我通常可以使用的解决方案是仅修改粘贴echo到前面可能造成任何损坏的语句。
这通常可以在典型的现实生活脚本中使用,因为(a)生成要迭代的项目列表或将变量设置为的值通常可以在不更改文件系统的情况下生成,并且(b)通常足以假设如果您确实运行了该命令,它将成功。
trap read debug并在每个执行的行之后进行读取,然后可以使用enter缓慢地执行该脚本(如果您的脚本很长并且要测试,则很有用。它是第一次)。
我认为您将不得不回显-但是,如果将命令放在变量中,则可以打开和关闭它。而且,该命令可以是功能,也可以是您想要的复杂功能。
#!/bin/bash
echo 'Debug'
D=echo
:>| testy
ls -l testy
$D rm -f testy
ls -l testy
echo $'\n\nLive'
D=
:>| testy
ls -l testy
$D rm -f testy
ls -l testy
!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
Live
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
ls: cannot access testy: No such file or directory
D=eval实时部分。但是很好的答案!
使用bash的-x选项来跟踪流,但这仍将执行命令。
最好的办法就是将echo或注释掉具有rm之类的外部影响的命令。至少您不必更改每一行。
我不知道任何特殊的空运行方法,但是我们可以采取一些预防措施来了解未知脚本。
bash -n <script>的语法检查。从gnu bash手册https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html -n
Read commands but do not execute them; this may be used to check a script for syntax errors. This option is ignored by interactive shells.
alias rm="rm -i"
alias cp="cp -i"
alias mv="mv -i"
对于sed之类的流编辑器
sed -i(-i在不使用-i的情况下修改文件,它对sed进行空运行,请查看手册页以了解详细信息)可以复制完整的命令并运行。在实际命令之前,它将在屏幕上显示输出,然后使用命令等待用户输入继续。示例
sed -i <pattern>
替换为
sed <pattern>
read -p "Press any key..."
sed -i <pattern>
另外,始终建议在系统中保留备份点,以便在紧急情况下可以恢复数据。
执行set –n或追加n到现有set –v命令。但是,由于这会导致外壳程序不评估任何命令,甚至不评估if或while,您可能对操作流程的了解不太好。
这是我喜欢使用的一些构造:
#!/bin/sh
verbose=false
really=true
# parse arguments
while [ $# -ge 1 ]
do
case "$1" in
-v) verbose=true ;;
-n) really=false; verbose=true ;;
esac
shift
done
doCmd() {
if $verbose; then echo "$@"; fi
if $really; then "$@"; fi
}
doCmd make foo
doCmd rm -rf /tmp/installdir
doCmd mkdir /tmp/installdir
doCmd whatever
doCmd blah blah
如果要防止发生修改,可以以没有特权的用户身份运行脚本:
sudo -u nobody ./scr.sh
在您的示例中,这将FN="filename"照常执行。尽管它在技术上也执行命令rm -f ${FN},但是如果没有权限删除该文件的必要权限,则不会发生任何事情。
当然,这将导致条件工作流程出现问题。rm命令失败的事实可能会影响脚本的其他部分。