bash echo 命令,然后运行它?(喜欢做)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12231792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:37:34  来源:igfitidea点击:

Echo command, and then run it? (Like make)

bashshellmakefileecho

提问by mjs

Is there some way to get bash into a sort of verbose mode where, such that, when it's running a shell script, it echoes out the command it's going to run before running it? That is, so that it's possible to see the commands that were run (as well as their output), similar to the output of make?

有没有办法让 bash 进入一种详细模式,这样,当它运行一个 shell 脚本时,它会在运行它之前回显它要运行的命令?也就是说,这样就可以看到运行的命令(以及它们的输出),类似于make?

That is, if running a shell script like

也就是说,如果运行一个 shell 脚本,比如

echo "Hello, World"

I would like the following output

我想要以下输出

echo "Hello, World"
Hello, World

Alternatively, is it possible to write a bash function called echo_and_runthat will output a command and then run it?

或者,是否可以编写一个名为 bash 的函数echo_and_run来输出命令然后运行它?

$ echo_and_run echo "Hello, World"
echo "Hello, World"
Hello, World

采纳答案by mjs

It's possible to use bash's printfin conjunction with the %qformat specifier to escape the arguments so that spaces are preserved:

可以将 bashprintf%q格式说明符结合使用来转义参数,以便保留空格:

function echo_and_run {
  echo "$" "$@"
  eval $(printf '%q ' "$@") < /dev/tty
}

回答by cnicutar

You could make your own function to echocommands before calling eval.

您可以echo在调用eval.

Bash also has a debugging feature. Once you set -xbash will display each command before executing it.

Bash 还具有调试功能。一旦你set -xbash 将在执行它之前显示每个命令。

cnicutar@shell:~/dir$ set -x
cnicutar@shell:~/dir$ ls
+ ls --color=auto
a  b  c  d  e  f

回答by Keith Thompson

To answer the second part of your question, here's a shell function that does what you want:

要回答问题的第二部分,这里有一个可以执行您想要的操作的 shell 函数:

echo_and_run() { echo "$*" ; "$@" ; }

I use something similar to this:

我使用类似的东西:

echo_and_run() { echo "$ $*" ; "$@" ; }

which prints $in front of the command (it looks like a shell prompt and makes it clearer that it's a command). I sometimes use this in scripts when I want to show some (but not all) of the commands it's executing.

它打印$在命令的前面(它看起来像一个 shell 提示,并且更清楚地表明它是一个命令)。当我想显示它正在执行的一些(但不是全部)命令时,我有时会在脚本中使用它。

As others have mentioned, it does lose quotation marks:

正如其他人所提到的,它确实失去了引号:

$ echo_and_run echo "Hello, world"
$ echo Hello, world
Hello, world
$ 

but I don't think there's any good way to avoid that; the shell strips quotation marks before echo_and_rungets a chance to see them. You could write a script that would check for arguments containing spaces and other shell metacharacters and add quotation marks as needed (which still wouldn't necessarily match the quotation marks you actually typed).

但我认为没有什么好方法可以避免这种情况;外壳在echo_and_run有机会看到它们之前去掉引号。您可以编写一个脚本来检查包含空格和其他 shell 元字符的参数并根据需要添加引号(它仍然不一定与您实际键入的引号匹配)。

回答by Toby Speight

Two useful shell options that can be added to the bashcommand line or via the setcommand in a script or interactive session:

可以添加到bash命令行或通过set脚本或交互式会话中的命令的两个有用的 shell 选项:

  • -vPrint shell input lines as they are read.
  • -xAfter expanding each simple command, forcommand, casecommand, selectcommand, or arithmetic forcommand, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.
  • -v在读取时打印 shell 输入行。
  • -x在展开每个简单命令、for命令、case命令、select命令或算术for命令后,显示 的展开值PS4,后跟命令及其展开的参数或关联的单词列表。

回答by agc

For extra timestamps and I/O info, consider the annotate-outputcommand from Debian's devscriptspackage:

有关额外的时间戳和 I/O 信息,请考虑annotate-output来自Debiandevscripts包的命令:

annotate-output echo hello

Output:

输出:

13:19:08 I: Started echo hello
13:19:08 O: hello
13:19:08 I: Finished with exitcode 0

Now look for a file that doesn't exist, and note the E:for STDERRoutput:

现在查找一个不存在的文件,并注意E:对于STDERR输出:

annotate-output ls nosuchfile

Output:

输出:

13:19:48 I: Started ls nosuchfile
13:19:48 E: ls: cannot access 'nosuchfile': No such file or directory
13:19:48 I: Finished with exitcode 2

回答by Fordi

To add to others' implementations, this is my basic script boilerplate, including argument parsing (which is important if you're toggling verbosity levels).

要添加到其他人的实现中,这是我的基本脚本样板,包括参数解析(如果您要切换详细级别,这很重要)。

#!/bin/sh

# Control verbosity
VERBOSE=0

# For use in usage() and in log messages
SCRIPT_NAME="$(basename 
vexec 1 "Building myapp.c" \
    gcc -c myapp.c -o build/myapp.o ${CFLAGS}
)" ARGS=() # Usage function: tells the user what's up, then exits. ALWAYS implement this. # Optionally, prints an error message # usage [{errorLevel} {message...} function usage() { local RET=0 if [ $# -gt 0 ]; then RET=; shift; fi if [ $# -gt 0 ]; then log "[$SCRIPT_NAME] ${@}" fi log "Describe this script" log "Usage: $SCRIPT_NAME [-v|-q]" # List further options here log " -v|--verbose Be more verbose" log " -q|--quiet Be less verbose" exit $RET } # Write a message to stderr # log {message...} function log() { echo "${@}" >&2 } # Write an informative message with decoration # info {message...} function info() { if [ $VERBOSE -gt 0 ]; then log "[$SCRIPT_NAME] ${@}" fi } # Write an warning message with decoration # warn {message...} function warn() { if [ $VERBOSE -gt 0 ]; then log "[$SCRIPT_NAME] Warning: ${@}" fi } # Write an error and exit # error {errorLevel} {message...} function error() { local LEVEL=; shift if [ $VERBOSE -gt -1 ]; then log "[$SCRIPT_NAME] Error: ${@}" fi exit $LEVEL } # Write out a command and run it # vexec {minVerbosity} {prefixMessage} {command...} function vexec() { local LEVEL=; shift local MSG=""; shift if [ $VERBOSE -ge $LEVEL ]; then echo -n "$MSG: " local CMD=( ) for i in "${@}"; do # Replace argument's spaces with ''; if different, quote the string if [ "$i" != "${i/ /}" ]; then CMD=( ${CMD[@]} "'${i}'" ) else CMD=( ${CMD[@]} $i ) fi done echo "${CMD[@]}" fi ${@} } # Loop over arguments; we'll be shifting the list as we go, # so we keep going until is empty while [ -n "" ]; do # Capture and shift the argument. ARG="" shift case "$ARG" in # User requested help; sometimes they do this at the end of a command # while they're building it. By capturing and exiting, we avoid doing # work before it's intended. -h|-\?|-help|--help) usage 0 ;; # Make the script more verbose -v|--verbose) VERBOSE=$((VERBOSE + 1)) ;; # Make the script quieter -q|--quiet) VERBOSE=$((VERBOSE - 1)) ;; # All arguments that follow are non-flags # This should be in all of your scripts, to more easily support filenames # that start with hyphens. Break will bail from the `for` loop above. --) break ;; # Something that looks like a flag, but is not; report an error and die -?*) usage 1 "Unknown option: '$ARG'" >&2 ;; # # All other arguments are added to the ARGS array. *) ARGS=(${ARGS[@]} "$ARG") ;; esac done # If the above script found a '--' argument, there will still be items in $*; # move them into ARGS while [ -n "" ]; do ARGS=(${ARGS[@]} "") shift done # Main script goes here.

Later...

之后...

#!/bin/bash
echo "$*"
$@

Note: This will not cover piped commands; you need to bash -c those sorts of things, or break them up into intermediate variables or files.

注意:这不会涵盖管道命令;你需要 bash -c 这些东西,或者把它们分解成中间变量或文件。

回答by Mayura

Create executable(+x) base script named as "echo_and_run" with below mentioned simple shell script!

使用下面提到的简单shell脚本创建名为“echo_and_run”的可执行(+x)基本脚本!

echo Hello, World
Hello, World

$ ./echo_and_run "echo Hello, World"

$ ./echo_and_run "echo Hello, World"

echo_and_run() { echo "$ $*" ; "$@" ; }

Or simply use one liner bash function.

或者干脆使用一个 liner bash 函数

function echo_and_run {
  echo "$" "$@"
  eval $(printf '%q ' "$@") < /dev/tty
}

Or even this variant would work:

甚至这个变体也能工作:

##代码##

However, cnicutar'sapproch to set -xis reliable and strongly recommended.

但是,cnicutar 的方法set -x是可靠的,强烈推荐。