How to echo shell commands as they are executed
在shell脚本中,如何回送调用的所有shell命令并展开任何变量名?
例如,给出以下行:
1 | ls $DIRNAME |
我希望脚本运行该命令并显示以下内容
1 | ls /full/path/to/some/dir |
目的是保存调用的所有shell命令及其参数的日志。有没有更好的方法来生成这样的日志?
使用
在脚本的第一行,可以将
以上也适用于
在
1 2 3 4 5 6 7 8 9 10 | $ cat shl #!/bin/bash DIR=/tmp/so ls $DIR $ bash -x shl + DIR=/tmp/so + ls /tmp/so $ |
下面是一个示例shell脚本,演示:
1 2 3 4 | #!/bin/bash set -x #echo on ls $PWD |
这将展开所有变量并在输出命令之前打印完整的命令。
输出:
1 2 | + ls /home/user/ file1.txt file2.txt |
您还可以将脚本中的select行包装在
1 2 3 4 5 6 7 8 9 | #!/bin/bash ... if [[ ! -e $OUT_FILE ]]; then echo"grabbing $URL" set -x curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE set +x fi |
我使用一个函数来回音,然后运行命令
1 2 3 4 5 | #!/bin/bash #function to display commands exe() { echo"\$ $@" ;"$@" ; } exe echo hello world |
哪些输出
1 2 | $ echo hello world hello world |
编辑:
对于更复杂的命令、管道等,可以使用eval:
1 2 3 4 5 | #!/bin/bash #function to display commands exe() { echo"\$ ${@/eval/}" ;"$@" ; } exe eval"echo 'Hello World' | cut -d ' ' -f1" |
哪些输出
1 2 | $ echo 'Hello World' | cut -d ' ' -f1 Hello |
Shuckc对回显select行的回答有一些缺点:您最终会得到如下的
另一个选项是在子shell中运行命令:
1 2 3 4 5 6 7 | echo"getting URL..." ( set -x ; curl -s --fail $URL -o $OUTFILE ) if [ $? -eq 0 ] ; then echo"curl failed" exit 1 fi |
这将为您提供如下输出:
1 2 3 | getting URL... + curl -s --fail http://example.com/missing -o /tmp/example curl failed |
但是,这会导致为命令创建新的子shell的开销。
另一个选项是将"-x"放在脚本顶部,而不是命令行上:
1 2 3 4 5 6 7 8 | $ cat ./server #!/bin/bash -x ssh user@server $ ./server + ssh user@server user@server's password: ^C $ |
(没有足够的代表对所选答案发表评论。)
根据TLDP的bash初学者指南:第2章。编写和调试脚本
2.3.1. Debugging on the entire script
1 $ bash -x script1.sh...
There is now a full-fledged debugger for Bash, available at SourceForge. These debugging features are available in most modern versions of Bash, starting from 3.x.
2.3.2. Debugging on part(s) of the script
1
2
3 set -x # activate debugging from here
w
set +x # stop debugging from here...
Table 2-1. Overview of set debugging options
1 2 3 4 5 | Short | Long notation | Result -------+---------------+-------------------------------------------------------------- set -f | set -o noglob | Disable file name generation using metacharacters (globbing). set -v | set -o verbose| Prints shell input lines as they are read. set -x | set -o xtrace | Print command traces before executing command. |
...
Alternatively, these modes can be specified in the script itself, by
adding the desired options to the first line shell declaration.
Options can be combined, as is usually the case with UNIX commands:
1 #!/bin/bash -xv
在命令行的bash脚本名称之前键入"bash-x"。例如,要执行foo.sh,请键入:
1 | bash -x foo.sh |
您可以使用-x选项在调试模式下执行bash脚本。这将回响所有命令。
1 2 3 4 5 | bash -x example_script.sh # Console output + cd /home/user + mv text.txt mytext.txt |
您还可以在脚本中保存-x选项。只需在shebang中指定-x选项。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ######## example_script.sh ################### #!/bin/bash -x cd /home/user mv text.txt mytext.txt ############################################## ./example_script.sh # Console output + cd /home/user + mv text.txt mytext.txt |
上面有人发帖:
1 2 3 | #!/bin/bash #function to display commands exe() { echo"\$ $@" ;"$@" ; } |
这看起来很有希望,但我一辈子都搞不清楚它的作用。我在man bash页面上搜索并搜索了"$"和"$@",结果一无所获。
我知道正在创建一个名为"exec()"的函数。我理解花括号标记函数的开始和结束。我认为我理解分号在多行命令之间标记一个"硬返回",因此"echo"$@";"$@";"本质上变成:
1 2 3 4 5 | { echo"\$ $@" "$@" } |
既然我的google fu显然让我失望了,有人能给我一个简短的解释,或者在哪里找到这个信息吗?
(不打算在旧线程上开始新问题,我的目标是将输出重新路由到文件。"set-x;[commands];set+x"方法对我来说可以很好地工作,但是我不知道如何将结果回送到文件而不是屏幕,所以我试图理解另一种方法,希望我对重定向/pipes/tee/等的理解非常差以完成相同的工作。)
谢谢!
后期编辑:
做了些小修补,我想我已经弄明白了。以下是我需要的等效代码:
1 2 3 4 5 6 7 8 9 | SCRIPT_LOG="\home\buddy\logfile.txt" exe () { params="$@" # Put all of the command-line into"params" printf"%s\t$params""$(date)">>"$SCRIPT_LOG" # Print the command to the log file $params # Execute the command } exe rm -rf /Library/LaunchAgents/offendingfile exe rm -rf /Library/LaunchAgents/secondoffendingfile |
logfile.txt中的结果如下:
1 2 | Tue Jun 7 16:59:57 CDT 2016 rm -rf /Library/LaunchAgents/offendingfile Tue Jun 7 16:59:57 CDT 2016 rm -rf /Library/LaunchAgents/secondoffendingfile |
只是我需要的。谢谢!
ZSH回波
1 | setopt VERBOSE |
用于调试
1 | setopt XTRACE |
对于
http://www.tcsh.org/tcsh.html/special_shell_variables.html_verbose
http://www.tcsh.org/tcsh.html/special_shell_variables.html echo
If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.
If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.
1 2 3 4 5 6 | $ cat exampleScript.sh #!/bin/bash name="karthik"; echo $name; bash -x exampleScript.sh |
输出如下:
为了允许复合命令被回送,我使用
没有EVA:
1 2 | exe() { echo"\$ $@" ;"$@" ; } exe ls -F | grep *.txt |
输出:
1 2 | $ file.txt |
用EVA:
1 2 | exe() { echo"\$ $@" ;"$@" ; } exe eval 'ls -F | grep *.txt' |
哪些输出
1 2 | $ exe eval 'ls -F | grep *.txt' file.txt |