如何在执行外壳命令时回显它们


910

在shell脚本中,如何回显所有被调用的shell命令并扩展任何变量名?

例如,给出以下行:

ls $DIRNAME

我希望脚本运行命令并显示以下内容

ls /full/path/to/some/dir

目的是保存所有调用的shell命令及其参数的日志。也许有更好的方法来生成这样的日志?

Answers:


1041

set -xset -o xtrace展开变量并在该行之前打印一点+号。

set -vset -o verbose在打印之前不展开变量。

使用set +xset +v关闭以上设置。

在脚本的第一行,可以将#!/bin/sh -x(或-v)效果与脚本的稍后set -x(或-v)效果相同。

以上也适用于/bin/sh

有关set属性调试,请参见bash-hackers的Wiki 。

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$

7
如果您还想查看正在执行的编号行,请参见stackoverflow.com/a/17805088/1729501
user13107 '18

3
如果要在回显以区分命令及其结果输出时给命令着色,该怎么办?
刘易斯·陈

10
如果我希望它在回声时通过类似人声的语音合成器来唱歌每个命令,以便我能从远处听到它在做什么并欣赏音乐,该怎么办?也许以不同的声音表示输入和输出。
ADJenks,

(ABS长期以来一直不响应他们纠正不良做法示例的请求,以至于驱使长期的社区成员创建竞争性资源;将链接移至bash-hacker的Wiki-Wooledge Wiki或官方bash手册也将是更好的资源)。
查尔斯·达菲,

316

set -x 会给你你想要的。

这是一个示例shell脚本来演示:

#!/bin/bash
set -x #echo on

ls $PWD

这将展开所有变量并在命令输出之前打印完整命令。

输出:

+ ls /home/user/
file1.txt file2.txt

21
那样使用“冗长”一词并不能完成任何事情。您可以执行set -o verboseset -v(仅“详细”)或set -o xtraceset -x(仅“ xtrace”)或set -xv(两者)或set -o xtrace -o verbose(两者)。
暂停,直到另行通知。

这很好,但请注意,“冗长的”覆盖$ 1
JasonS 2013年

90

我使用一个函数来回显并运行命令:

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

这个答案的选票不多。有一个不好的主意吗?为我工作,似乎正是我在寻找的东西
fru1tbat 2014年

1
如果您不希望打印所有命令,这是最佳答案。它避免了++ set +x关闭电源时的输出,并且看起来更干净。但是,对于仅一个或两个语句,使用子shell的bhassel答案是最方便的。
布伦特·浮士德·浮士德2015年

这就是我要的!不set +x,它影响所有命令,太多了!
Hlung

11
这样做的主要缺点是输出会丢失报价信息。例如,您无法区分cp "foo bar" bazcp foo "bar baz"。因此,向用户显示进度信息非常有用;调试输出或记录可重现命令的内容更少。不同的用例。在中zsh,您可以保留带:q修饰符的引号:exe() { echo '$' "${@:q}" ; "$@" ; }
Andrew Janke

2
我不喜欢这个答案。在很多情况下,您看到的不是您得到的(尤其是空格,引号,转义字符,变量/表达式替换等),因此请不要盲目地将echoed命令粘贴到终端中并假定它将运行一样的方法。另外,第二种技术只是破解,它将eval从命令中删除单词的其他实例。因此,不要指望它能正常工作exe eval "echo 'eval world'"
mwfearnley

88

您还可以通过将它们包装在set -xset +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

54

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

但是,这确实会产生为命令创建新的子外壳的开销。


7
避免++ set +x输出的好方法。
布伦特·浮士德2015年

3
更好的是:替换if [ $? -eq 0 ]if (set -x; COMMAND)
Amedee Van Gasse

35

另一个选择是在脚本的顶部而不是在命令行的顶部放置“ -x”:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$

请注意,在./myScript和之间,这似乎并不完全相同bash myScript。还是要指出一件好事,谢谢。
altendky 2015年

27

根据TLDPBash初学者指南:第2章。编写和调试脚本

2.3.1。在整个脚本上调试

$ bash -x script1.sh

...

现在,可以在SourceForge上使用Bash的完整调试器。从3.x开始,大多数现代版本的Bash中都提供了这些调试功能。

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

18

在Bash脚本名称之前的命令行上键入“ bash -x”。例如,要执行foo.sh,请输入:

bash -x foo.sh

11

您可以使用选项在调试模式下执行 Bash脚本-x

这将回显所有命令。

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

您也可以将-x选项保存在脚本中。只需-x在shebang中指定选项即可。

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

2
bash -vx将执行相同的操作,但没有变量插值
loa_in_18年

4

对于zsh,回显

 setopt VERBOSE

对于调试,

 setopt XTRACE

2

对于cshtcsh,您可以set verboseset 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.



1

为了让复合命令得到回应,我使用了evalSoth的exe函数并运行命令。这对于管道命令很有用,否则管道命令将仅显示不显示或仅显示管道命令的初始部分。

没有评估:

exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt

输出:

$
file.txt

与评估:

exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'

哪个输出

$ exe eval 'ls -F | grep *.txt'
file.txt
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.