Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 使用可见的引号回显传递给命令的确切命令行_Bash_Quoting - Fatal编程技术网

Bash 使用可见的引号回显传递给命令的确切命令行

Bash 使用可见的引号回显传递给命令的确切命令行,bash,quoting,Bash,Quoting,因此,我可以非常愉快地将命令行构建到bash数组中,然后使用引号执行它,并使每个参数都被正确引用: declare -a cmd_args cmd_args=("-p" "dir path/with spaces") mkdir "${cmd_args[@]}" echo dir*/* 但是我怎样才能让它以一种有意义的方式在屏幕上得到回应——即向用户显示一条命令,然后他们可以键入,或者我可以将其保存在日志文件中以备将来参考?所有这些看起来(基本上)相同: echo runnimg mkdir

因此,我可以非常愉快地将命令行构建到bash数组中,然后使用引号执行它,并使每个参数都被正确引用:

declare -a cmd_args
cmd_args=("-p" "dir path/with spaces")
mkdir "${cmd_args[@]}"
echo dir*/*
但是我怎样才能让它以一种有意义的方式在屏幕上得到回应——即向用户显示一条命令,然后他们可以键入,或者我可以将其保存在日志文件中以备将来参考?所有这些看起来(基本上)相同:

echo runnimg mkdir with arguments ${cmd_args[@]}
echo runnimg mkdir with arguments "${cmd_args[@]}"
echo "runnimg mkdir with arguments '${cmd_args[@]}'"
echo "runnimg mkdir with arguments '${cmd_args[*]}'"

==> runnimg mkdir with arguments '-p dir path/with spaces'
这显然是错误的命令。这并不是向用户显示一个命令,然后他们可以键入该命令,或者我可以将其保存在日志文件中,并在将来的某个日期复制该命令。我想看看:

runnimg mkdir with arguments '"-p" "dir path/with spaces"'

如果要打印每个参数都被引用的参数列表,不管引用是否合适,我考虑使用
cat:

printf'%s''${cmd_args[@]}

如果要仅在需要时打印带引号或转义的参数列表:

printf'%q'${cmd_args[@]}
你要做的是:

printf'runnimg mkdir和参数:'
printf'%q'${cmd_args[@]}
与POSIX外壳兼容的实现:

#/usr/垃圾箱/环境破折号
#cmd_args=(“-p”“dir path/带空格”)
#dash和POSIX shell没有数组
#但支持如下设置参数:
设置--p“dir path/with spaces”
printf'runnimg mkdir带参数:'
#dash内置printf不知道%q格式,
#但系统命令printf可以。
环境打印文件“%q'”$@
回声
mkdir“$@”

您可以使用
声明-p

$ cmd_args=("-p" "dir path/with spaces")
$ declare -p cmd_args
declare -a cmd_args=([0]="-p" [1]="dir path/with spaces")
或者使用
%q
格式化指令:

$ printf '%q\n' "${cmd_args[@]}"
-p
dir\ path/with\ spaces
基于:

#/bin/bash
trap'printf RUNNING:\%s\\n“$BASH\u命令”>&2'调试
foo(){
printf'%s\n'$@>/dev/null
}
福吧巴兹酒店
foo'qux bazinga'12'3'4 5'
“我要回家了”
调试
陷阱输出:

RUNNING: foo bar baz
RUNNING: foo 'qux bazinga' '1 2' 3 '4 5'
RUNNING: foo "I'm going home"
显示脚本中出现的引号

函数
foo
设置为输出为
/dev/null
,因此我们可以忽略其输出。它只是脚本实际运行的任何命令的替身

下面是一个版本,它将
陷阱
代码放入一个函数中,并调用该函数来打开和关闭陷阱。如果您只希望陷阱处理某些代码段,则此选项非常有用:

#/bin/bash
dbt(){
如果[$1==on]]
然后
trap'printf RUNNING:\%s\\n“$BASH\u命令”>&2'调试
elif[[$1==关闭]]
然后
陷阱“”调试
其他的
printf“%s\n”无效操作:$1
fi
}
foo(){
printf'%s\n'$@>/dev/null
}
福吧巴兹酒店
dbt on
foo'qux bazinga'12'3'4 5'
“我要回家了”
现在=$(日期)
dbt关闭
声明-a数组
dbt on
数组_b=(a b'c d'e)
哪些产出:

RUNNING: foo 'qux bazinga' '1 2' 3 '4 5'
RUNNING: foo "I'm going home"
RUNNING: now=$(date)
RUNNING: dbt off
RUNNING: array_b=(a b 'c d' e)
跟踪脚本执行的另一种方法是使用

在展开命令后和执行命令前,打印简单命令的跟踪,例如命令、大小写命令、选择命令和命令及其参数的算术或相关单词列表。PS4变量的值将展开,结果值将在命令及其展开参数之前打印


'%q'
方法非常好,因为它在视觉上是明确的,并且以一种可以复制粘贴到不同shell中的方式捕获有关参数的所有信息<如果参数包含例如
$
”,则代码>““%s”
将不起作用
%q
格式将生成可以粘贴到bash中的内容,但不一定要粘贴到其他shell中。例如,如果字符串包含非打印字符,则倾向于使用ANSI引用模式(例如,
$'\t'
for tab)--这在视觉上是清晰的,但在基本的shell类型的破折号中不起作用。是的,预期的意思是“%q允许用户通过将执行复制粘贴到第二个shell实例中来轻松地再现执行”,而不是“%q”对于在不同的shell实现之间移植脚本很有用"@Gordon Davisson我添加了一个
dash
/POSIX兼容的实现事实上,出于我的目的,我使用了%q,但是调试的东西更准确!但是这仍然没有用引号向用户显示带空格的参数?I/.e它没有向用户显示他们可以键入的命令,或者我可以保存在日志文件中的命令。更新问题,因为很明显我的意图是错误的。@gemtylor好吧,
%q
不会在整个字符串周围显示漂亮的引号,而是分别对每个字符进行转义(就像在莱娅的第二个答案中),但该输出可以直接重新用作shell命令。这会捕获所有发出的命令或所有内部函数调用?我想这比我目前拥有的要好,谢谢,特别是因为我不太倾向于使用函数。尽管我只想担心“主要”命令:-)@GemTaylor:它将捕获所有执行的命令,例如,问题中第一个代码块中的所有命令。您可以启用和禁用要专门输出的代码部分周围的陷阱。我将在我的答案中添加一个例子。我只是为了演示一些简单的东西才包含这个函数。但是,通过减少重复,函数对于代码组织和可维护性非常有用。我希望明天可以使用它。让我们看看对于引号扩展的数组,如果输出是什么…@GemTaylor:调试陷阱是在执行任何处理之前运行的,包括变量扩展和引号删除。
RUNNING: foo 'qux bazinga' '1 2' 3 '4 5'
RUNNING: foo "I'm going home"
RUNNING: now=$(date)
RUNNING: dbt off
RUNNING: array_b=(a b 'c d' e)