如何从 shell 获取准确的命令行字符串?
Posted
技术标签:
【中文标题】如何从 shell 获取准确的命令行字符串?【英文标题】:How to get exact command line string from shell? 【发布时间】:2014-07-17 23:01:39 【问题描述】:我知道$*
、$@
、"$@"
甚至$1+"@"
以及它们的含义。
我需要从 shell 脚本访问 EXACT 命令行参数字符串。请注意示例中的引号。像“$@”这样的东西会保存参数但会删除引号,我不知道如何从中恢复。
例子:
./my-shell.sh "1 2" 3
而且我需要在不进行任何处理的情况下检索 EXACT 参数字符串:
“1 2”3
知道如何实现吗?
【问题讨论】:
您是否能够分别获取命令行参数1 2
和3
?如果可以的话,只需将引号添加回第一个参数,然后将两个参数混在一起。
Preserving quotes in bash function parameters 的可能重复项
@RobertHarvey 但是在 "1 2" 3
的情况下如何区分带引号和不带引号的参数?我只需要'原始'字符串。如果我收到1 2 4
,我真的需要1 2 4
,而不是1 2 4
。
如果 1 2
被引用了,你难道不把它作为一个单独的参数吗?
这本质上是不可能的,调用 shell 脚本的 shell 会解释命令行字符串并相应地将参数传递给 shell 脚本。换句话说,没有 Unix 程序可以访问调用它的确切命令行,只能访问命令行包含的参数。要看看它在实践中是如何工作的,我推荐strace -f
ing 你的 shell,因为它会启动一个 shell 脚本;特别注意 execve
调用,它将子进程的控制权转移到脚本。
【参考方案1】:
在bash
中,您可以从 shell 历史记录中获取:
set -o history
shopt -s expand_aliases
function myhack
line=$(history 1)
line=$line#*[0-9]
echo "You wrote: $line"
alias myhack='myhack #'
如你所描述的那样工作:
$ myhack --args="stuff" * 1..10 $PATH
You wrote: myhack --args="stuff" * 1..10 $PATH
另外,这里有一个方便的图表:
【讨论】:
别名和历史都可以在脚本中启用;它们只是默认关闭。 可爱的图表。但是我需要准确地重现用户输入的命令行,以便能够以编程方式重新执行它以防失败。我认为这属于“其他”。哦,当然,我可以编写自己的算法来根据需要正确再现(嵌套)引号。但如果这个想法没有敲响警钟,我不知道会怎样。 (不幸的是,您的解决方案对我不起作用,因为历史记录已关闭并且在脚本中打开它为时已晚。) @KonradRudolph 如果您想捕获非参数(如重定向和管道)或者您想重新评估代码(以便重新运行yourscript "$(date +%F).$RANDOM.txt"
将使用新的日期和随机数而不是原始运行)。
@KonradRudolph,为什么需要重现输入,而不是重现输入解析到的数组,或者生成解析到同一个数组的不同可能输入?
@CharlesDuffy 因为所述数组不包含重定向,也不包含命令管道的其他部分。【参考方案2】:
但我需要准确地重现用户输入的命令行,以便能够以编程方式重新执行它以防失败
您不需要确切的命令行;您可以自己重建一个等效的(即使不相同!)shell 命令。
#!/usr/bin/env bash
printf -v cmd_q '%q ' "$@"
echo "Executed with a command identical to: $cmd_q"
...虽然你甚至不需要 那个,因为 "$@"
可以按原样重新执行,而不知道启动它的命令是什么:
#!/usr/bin/env bash
printf "Program is starting; received command line equivalent to: "
printf '%q ' "$@"
printf '\n'
if [[ ! $already_restarted ]]; then
echo "About to restart ourselves:
exec "$@" # restart the program
fi
【讨论】:
以上是关于如何从 shell 获取准确的命令行字符串?的主要内容,如果未能解决你的问题,请参考以下文章