在shell脚本中,如何回显所有调用的shell命令并展开任何变量名?
例如,给定以下行:
ls $DIRNAME
我希望脚本能够运行命令并显示以下内容
ls /full/path/to/some/dir
目的是保存所有调用的shell命令及其参数的日志。是否有更好的方法来生成这样的日志?
答案 0 :(得分:820)
set -x
或set -o xtrace
扩展变量并在该行前打印一个小符号。
set -v
或set -o verbose
在打印前不会展开变量。
使用set +x
和set +v
关闭上述设置。
在脚本的第一行,可以让#!/bin/sh -x
(或-v
)与脚本中的set -x
(或-v
)具有相同的效果
以上内容也适用于/bin/sh
。
在set
attributes和debugging上查看bash-hackers的维基。
$ cat shl
#!/bin/bash
DIR=/tmp/so
ls $DIR
$ bash -x shl
+ DIR=/tmp/so
+ ls /tmp/so
$
答案 1 :(得分:273)
set -x
会给你你想要的东西。
以下是一个示例shell脚本:
#!/bin/bash
set -x #echo on
ls $PWD
这将扩展所有变量并在输出命令之前打印完整命令。
输出:
+ ls /home/user/
file1.txt file2.txt
答案 2 :(得分:79)
您还可以通过将其包裹在set -x
和set +x
中来为脚本中的选定行切换此内容,例如
#!/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
答案 3 :(得分:71)
我使用函数回显然后运行命令
#!/bin/bash
#function to display commands
exe() { echo "\$ $@" ; "$@" ; }
exe echo hello world
哪个输出
$ echo hello world
hello world
编辑:
对于更复杂的命令管道等,您可以使用eval:
#!/bin/bash
#function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }
exe eval "echo 'Hello World' | cut -d ' ' -f1"
哪个输出
$ echo 'Hello World' | cut -d ' ' -f1
Hello
答案 4 :(得分:46)
shuckc回应选择行的答案有一些缺点:您最终还会回显以下set +x
命令,并且您失去了使用$?
测试退出代码的能力,因为它得到了由set +x
覆盖。
另一种选择是在子shell中运行命令:
echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )
if [ $? -eq 0 ] ; then
echo "curl failed"
exit 1
fi
将为您提供如下输出:
getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed
这确实会产生为命令创建新子shell的开销。
答案 5 :(得分:32)
另一种选择是将“-x”放在脚本的顶部而不是命令行:
$ cat ./server
#!/bin/bash -x
ssh user@server
$ ./server
+ ssh user@server
user@server's password: ^C
$
(对于所选答案的评论不足。)
答案 6 :(得分:19)
根据TLDP的Bash Guide for Beginners: Chapter 2. Writing and debugging scripts
<强> 2.3.1。调试整个脚本
$ bash -x script1.sh
...
现在有一个完整的Bash调试器,可在SourceForge获得。大多数现代版本的Bash都提供这些调试功能,从3.x开始。
<强> 2.3.2。调试脚本的部分
set -x # activate debugging from here w set +x # stop debugging from here
...
表2-1。设置调试选项概述
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.
...
或者,可以在脚本本身中指定这些模式 将所需选项添加到第一行shell声明中。 可以组合选项,通常是UNIX命令的情况:
#!/bin/bash -xv
答案 7 :(得分:17)
在bash脚本名称前的命令行上键入“bash -x”。例如,要执行foo.sh,请键入:
bash -x foo.sh
答案 8 :(得分:8)
您可以使用 -x选项在调试模式下执行 bash脚本。
这将回应所有命令。
bash -x example_script.sh
# Console output
+ cd /home/user
+ mv text.txt mytext.txt
您还可以在脚本中保存-x选项。只需在shebang中指定-x选项。
######## 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
答案 9 :(得分:5)
上面发布的人:
#!/bin/bash
#function to display commands
exe() { echo "\$ $@" ; "$@" ; }
这看起来很有希望,但我不能为我的生活弄清楚它的作用。我在man bash页面搜索并搜索&#34; \ $&#34;和&#34; $ @&#34;,并且绝对找不到没有。
我理解正在创建一个函数,名为&#34; exec()&#34;。我理解花括号标记了函数的开头和结尾。我想我明白,分号标志着&#34;艰难的回归&#34;在多行命令之间,以便&#39; {echo&#34; \ $ $ @&#34; ; &#34; $ @&#34; ; }&#39;变本质上:
{
echo "\$ $@"
"$@"
}
任何人都可以给我一个简短的解释,或者在哪里可以找到这些信息,因为很明显我的google-fu让我失望了吗?
(没有意义在旧线程上开始一个新问题,我的目标是将输出重新路由到文件。&#34; set -x; [commands]; set + x&#34;方法可以正常工作对我来说很好,但我无法弄清楚如何将结果回显到文件而不是屏幕,所以我试图理解这个其他方法,希望我能用我对重定向/管道/三通的理解很差/ etc做同样的事情。)
谢谢!
LATER EDIT:
经过一些修补,我相信我弄明白了。这是我所需要的等效代码:
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中的结果类似于:
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
正是我需要的。谢谢!
答案 10 :(得分:3)
对于zsh echo
setopt VERBOSE
和调试
setopt XTRACE
答案 11 :(得分:2)
对于csh
和tcsh
,您可以set verbose
或set echo
(或者您甚至可以设置两者,但在大多数情况下可能会导致一些重复)。
verbose
选项打印出您键入的确切shell表达式。
echo
选项更能说明通过产卵将执行的内容。
http://www.tcsh.org/tcsh.html/Special_shell_variables.html#verbose
http://www.tcsh.org/tcsh.html/Special_shell_variables.html#echo
Special shell variables
verbose
If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.
echo
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.
答案 12 :(得分:1)
为了允许回显复合命令,我使用eval
加上Soth的exe
函数进行回显,然后运行命令。这对于管道命令非常有用,否则管道命令只能显示或只显示管道命令的初始部分。
没有评估:
exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt
输出:
$
file.txt
使用eval:
exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'
哪个输出
$ exe eval 'ls -F | grep *.txt'
file.txt
答案 13 :(得分:1)
答案 14 :(得分:1)
结合所有答案,我发现这是最好的
exe(){
set -x
"$@"
{ set +x; } 2>/dev/null
}
# example
exe go generate ./...
{ set +x; } 2>/dev/null
来自https://stackoverflow.com/a/19226038/8608146