我想实现一个bash函数,它将其参数作为命令运行,而(可能选择)之前打印命令。想想安装脚本或测试运行器脚本。
只需使用
function run () {
echo "Running $@"
"$@"
}
不允许我区分来自run foo arg1 arg2
和run foo "arg1 arg2"
的来电,因此我需要正确地撤销参数。
到目前为止,我最好的拍摄是
function run () {
echo -n "Running"
printf " %q" "$@"
echo
"$@"
}
哪个有效:
$ run echo "one_argument" "second argument" argument\"with\'quotes
Running echo one_argument second\ argument argument\"with\'quotes
one_argument second argument argument"with'quotes
但不是很优雅。如何实现
的输出$ run echo "one_argument" "second argument" argument\"with\'quotes
Running echo one_argument "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
即。如何让printf
在需要引用的参数周围加上引号,并在其中正确地转义引号,以便输出可以正确复制?
答案 0 :(得分:3)
这将引用一切:
run() {
printf "Running:"
for arg; do
printf ' "%s"' "${arg//\"/\\\"}"
done
echo
"$@"
}
run echo "one_argument" "second argument" argument\"with\'quotes
Running: "echo" "one_argument" "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
此版本仅引用包含双引号或空格的参数:
run() {
local fmt arg
printf "Running:"
for arg; do
[[ $arg == *[\"[:space:]]* ]] && fmt=' "%s"' || fmt=" %s"
printf "$fmt" "${arg//\"/\\\"}"
done
echo
"$@"
}
run echo "one_argument" "second argument" argument\"with\'quotes
Running: echo one_argument "second argument" "argument\"with'quotes"
one_argument second argument argument"with'quotes
答案 1 :(得分:2)
我认为没有一个优雅的解决方案可以满足您的需求,因为"$@"
由bash
在任何命令看到之前由#!/bin/bash
function run() {
echo -n "Running:"
for arg in "$@"; do
arg="$(sed 's/"/\\&/g' <<<$arg)"
[[ $arg =~ [[:space:]\\\'] ]] && arg=\"arg\"
echo -n " $arg"
done
echo ""
"$@"
}
run "$@"
处理。您必须手动重新构建命令行:
$ ./test.sh echo arg1 "arg 2" "arg3\"with'other\'\nstuff"
Running: echo arg1 "arg 2" "arg3\"with'other\'\nstuff"
arg1 arg 2 arg3"with'other\'\nstuff
输出:
bash
请注意,在某些极端情况下,您将无法获得确切的输入命令行。当你传递$ ./test.sh echo foo'bar'baz
Running: echo foobarbaz
foobarbaz
$ ./test.sh echo "foo\\bar"
Running: echo "foo\bar"
foobar
在传递它们之前扩展的参数时会发生这种情况,例如:
{{1}}