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

问题描述 投票:720回答:14

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

例如,给定以下行:

ls $DIRNAME

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

ls /full/path/to/some/dir

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

bash shell sh posix trace
14个回答
836
投票

set -xset -o xtrace扩展变量并在该行之前打印一个小+符号。

set -vset -o verbose在打印前不会扩展变量。

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

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

以上也适用于/bin/sh

set attributesdebugging上查看bash-hackers的wiki。

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

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

5
投票

上面发布的人:

#!/bin/bash
#function to display commands
exe() { echo "\$ $@" ; "$@" ; }

这看起来很有希望,但我不能为我的生活弄清楚它的作用。我在Google bash页面搜索并搜索了“\ $”和“$ @”,并且一无所获。

我知道正在创建一个名为“exec()”的函数。我理解花括号标记了函数的开头和结尾。我想我明白,分号标志着多行命令之间的“硬回程”,所以'{echo“\ $ $ @”; “$ @”;从本质上说:

{
echo "\$ $@"
"$@"

}

任何人都可以给我一个简短的解释,或者在哪里可以找到这些信息,因为很明显我的google-fu失败了吗?

(没有意义在旧线程上开始一个新问题,我的目标是将输出重新路由到文件。“set -x; [commands]; set + x”方法对我来说效果很好,但我可以' t弄清楚如何将结果回显到文件而不是屏幕,所以我试图理解这个其他方法,希望我可以使用非常糟糕的理解重定向/管道/ tee /等来做同样的事情。)

谢谢!

后期编辑:

经过一些修补,我相信我弄明白了。这是我需要的等效代码:

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

正是我需要的。谢谢!


3
投票

对于zsh echo

 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
投票

为了允许回复复合命令,我使用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

1
投票
$ cat exampleScript.sh
#!/bin/bash
name="karthik";
echo $name;

bash -x exampleScript.sh

输出如下:

enter image description here


275
投票

set -x会给你你想要的东西。

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

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

ls $PWD

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

输出:

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

81
投票

你也可以通过将它们包装在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

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

47
投票

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的开销。


33
投票

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

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

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

(对于所选答案的评论不足。)


19
投票

根据TLDPBash 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

17
投票

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

bash -x foo.sh

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

© www.soinside.com 2019 - 2024. All rights reserved.