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
Echo command, and then run it? (Like make)
提问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_run
that 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 printf
in conjunction with the %q
format 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 echo
commands before calling eval
.
您可以echo
在调用eval
.
Bash also has a debugging feature. Once you set -x
bash will display each command before executing it.
Bash 还具有调试功能。一旦你set -x
bash 将在执行它之前显示每个命令。
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_run
gets 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 bash
command line or via the set
command in a script or interactive session:
可以添加到bash
命令行或通过set
脚本或交互式会话中的命令的两个有用的 shell 选项:
- -vPrint shell input lines as they are read.
- -xAfter expanding each simple command,
for
command,case
command,select
command, or arithmeticfor
command, display the expanded value ofPS4
, 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-output
command from Debian's devscriptspackage:
有关额外的时间戳和 I/O 信息,请考虑annotate-output
来自Debian的devscripts包的命令:
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 -x
is reliable and strongly recommended.
但是,cnicutar 的方法set -x
是可靠的,强烈推荐。