如何在bash shell脚本中回显命令,但不执行命令?


11

是否可以通过回显命令来运行Shell脚本,实际上不执行这些命令?

假设我有脚本删除名称存储在变量中的文件:

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

添加set -v将在执行前回显以下命令:

$ ./scr.sh
FN="filename"
rm -f ${FN}

现在,我想看看没有实际删除文件的该脚本的流程。IOW,我想防止对外部环境和文件系统的任何影响。这可能吗?

我可以用命令包装所有命令echo,但冗长的脚本很累人。


我不是bash脚本编写专家,但是如果我用另一种编程语言编写该代码,则会将所有命令存储在一个数组中。这样,应该很容易遍历并执行命令或打印输出。
雨果·德·亨里格2014年

Answers:


8

如果没有实际执行脚本,就无法单步执行脚本以查看其执行方式。在您的示例中,没有if语句或循环。但是在实际的脚本中,通常会有很多条件语句。将采用哪个分支通常取决于外壳程序运行前一个命令时发生的情况。如果它不运行该命令,则外壳程序将无法知道它将产生什么输出或返回代码是什么,下一个条件分支或赋值语句可能依赖于该输出。

如果重点是您想仔细检查一个脚本并在运行之前知道它的功能,那不是一个坏主意。但实际上,实现此目标的最佳方法是仅使用lessvi或类似方式浏览文件。

添加

如果您正在开发脚本,并且想在第一时间完成脚本,测试逻辑但如果遇到错误则不做任何破坏,我通常可以使用的解决方案是仅修改粘贴echo到前面可能造成任何损坏的语句。

这通常可以在典型的现实生活脚本中使用,因为(a)生成要迭代的项目列表或将变量设置为的值通常可以在不更改文件系统的情况下生成,并且(b)通常足以假设如果您确实运行了该命令,它将成功。


谢谢。正是由于您提到的原因,如果有一种方法会让我感到惊讶,但是无论如何,我还是决定尝试一下。这样做的原因是我正在开发一个脚本,该脚本可在网络中的许多计算机之间移动文件并在远程主机上执行某些操作。在实际将更改提交到文件系统之前,我想先看一下脚本的流程。遍历所有远程计算机以更正文件错误也将很乏味……
ysap 2013年

1
附加说明:要逐步执行脚本,可以启动该脚本,trap read debug并在每个执行的行之后进行读取,然后可以使用enter缓慢地执行该脚本(如果您的脚本很长并且要测试,则很有用。它是第一次)。
netigger

8

我认为您将不得不回显-但是,如果将命令放在变量中,则可以打开和关闭它。而且,该命令可以是功能,也可以是您想要的复杂功能。

#!/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


我需要在echo / don-t-echo命令中加上引号,然后再将其用于D=eval实时部分。但是很好的答案!
2014年

5

使用bash的-x选项来跟踪流,但这仍将执行命令。

最好的办法就是将echo或注释掉具有rm之类的外部影响的命令。至少您不必更改每一行。


谢谢。我在问题中提到了该选项,但它并不能真正解决我的问题。
ysap 2013年

抱歉,我认为您的意思是回显每一行,-x会将其简化为一些命令并向您显示评估结果。
parkydr

4

我不知道任何特殊的空运行方法,但是我们可以采取一些预防措施来了解未知脚本。

  1. 使用chroot环境运行调试脚本。它将充当沙箱,并提供保护以防止删除/修改主系统文件。
  2. 使用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.

  1. 至少读取一次脚本。您可以使用echo语句进行调试,user191016的答案中所述
    • 提防可疑或危险代码。
    • 例如与rm有关,影响/ dev / sda的命令等。
  2. 始终尝试以普通用户身份运行脚本,避免以root用户身份运行未知脚本。
  3. 您可以定义别名以使命令可以在脚本开始时将文件修改为交互式,例如 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>

另外,始终建议在系统中保留备份点,以便在紧急情况下可以恢复数据。


3

执行set –n或追加n到现有set –v命令。但是,由于这会导致外壳程序不评估任何命令,甚至不评估ifwhile,您可能对操作流程的了解不太好。


谢谢。这是一个好的开始,但是正如您所提到的,它并不能让我看到实际的流程-在我的真实脚本中,我遍历了远程主机列表。
ysap 2013年

3

这是我喜欢使用的一些构造:

#!/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

2

如果要防止发生修改,可以以没有特权的用户身份运行脚本:

sudo -u nobody ./scr.sh

在您的示例中,这将FN="filename"照常执行。尽管它在技术上也执行命令rm -f ${FN},但是如果没有权限删除该文件的必要权限,则不会发生任何事情。

当然,这将导致条件工作流程出现问题。rm命令失败的事实可能会影响脚本的其他部分。


我们永远不会理解的事情:为什么需要root才能以无人身份运行...
mjohnsonengr 2014年

用户“ nobody”不是操作系统的专有名词,但是您可以在sudoers文件中添加一个条目,以允许“ nobody”使用无密码的sudo。
丹尼斯

我不知道。脚本似乎由于某种错误或其他原因而在终止之前终止。
爱德华·福尔克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.