在字符串中使用 `$@` 参数时如何将它们分开?
how to keep `$@` arguments seperated when using them in a string?
嘿,我正在为 git 编写一个包装脚本,它将一个 git 命令应用于它的所有子模块,例如:supergit commit -m "change message"
提交给所有子模块。
该脚本主要执行以下操作:
function git_foreach () {
git submodule foreach "git \"$@\" || : "
}
git_foreach "$@"
问题是当 supergit 调用包含一个带有 spaces 的参数时(就像在上面的提交消息中一样),space 分隔的调用被解释为多个参数。
我在这个 answer 中读到,这样做的方法是使用 "$@"
但这在字符串中不起作用。
有没有办法扩展 $@
以保留引号,以便我的函数按预期工作?
编辑:
我想要的是将参数传递给 git submodule foreach
,用 supergit commit -m "commit message"
我想 运行:
git submodule foreach "git commit -m \"commit message\""
如果您的 /bin/sh
由 Bash
提供
printf %q
将生成一个正确转义的数据版本,以便由 shell.
解析
printf '%q ' "$@"
为数组中的每个参数生成一个包含单独 shell-escaped 单词的字符串,每个单词后有空格。
因此:
git_foreach() {
local cmd_q
printf -v cmd_q '%q ' "$@"
git submodule foreach "git $cmd_q ||:"
}
...或者,使用 bash 5.0 或更新版本(增加了 ${var@Q}
扩展),我们可以制作这一行:
git_foreach() { git submodule foreach "git ${@@Q} ||:"; }
对于 printf %q
的当前实现,git_foreach commit -m "commit message"
调用 git submodule foreach 'git commit -m commit\ message'
或语义等价物;转义与您手写的方式不同,但命令的效果完全相同。
如果您需要更广泛的兼容性
不幸的是,printf %q
和较新的 ${variable@Q}
扩展都能够生成使用 bash-only 语法的字符串(尤其是当您的字符串包含换行符、制表符或类似内容时)。如果您不控制 shell git 开始 运行 foreach
命令,那么我们需要生成一个字符串,该字符串被转义以供任何 POSIX-compliant 使用shell.
Bash 没有这样做的功能...但是 Python 有!
posix_escape() {
python3 -c 'import sys, shlex; print(" ".join([shlex.quote(s) for s in sys.argv[1:]]))' "$@"
}
git_foreach() {
local cmd_q
cmd_q=$(posix_escape "$@")
git submodule foreach "git $cmd_q ||:"
}
嘿,我正在为 git 编写一个包装脚本,它将一个 git 命令应用于它的所有子模块,例如:supergit commit -m "change message"
提交给所有子模块。
该脚本主要执行以下操作:
function git_foreach () {
git submodule foreach "git \"$@\" || : "
}
git_foreach "$@"
问题是当 supergit 调用包含一个带有 spaces 的参数时(就像在上面的提交消息中一样),space 分隔的调用被解释为多个参数。
我在这个 answer 中读到,这样做的方法是使用 "$@"
但这在字符串中不起作用。
有没有办法扩展 $@
以保留引号,以便我的函数按预期工作?
编辑:
我想要的是将参数传递给 git submodule foreach
,用 supergit commit -m "commit message"
我想 运行:
git submodule foreach "git commit -m \"commit message\""
如果您的 /bin/sh
由 Bash
提供
printf %q
将生成一个正确转义的数据版本,以便由 shell.
printf '%q ' "$@"
为数组中的每个参数生成一个包含单独 shell-escaped 单词的字符串,每个单词后有空格。
因此:
git_foreach() {
local cmd_q
printf -v cmd_q '%q ' "$@"
git submodule foreach "git $cmd_q ||:"
}
...或者,使用 bash 5.0 或更新版本(增加了 ${var@Q}
扩展),我们可以制作这一行:
git_foreach() { git submodule foreach "git ${@@Q} ||:"; }
对于 printf %q
的当前实现,git_foreach commit -m "commit message"
调用 git submodule foreach 'git commit -m commit\ message'
或语义等价物;转义与您手写的方式不同,但命令的效果完全相同。
如果您需要更广泛的兼容性
不幸的是,printf %q
和较新的 ${variable@Q}
扩展都能够生成使用 bash-only 语法的字符串(尤其是当您的字符串包含换行符、制表符或类似内容时)。如果您不控制 shell git 开始 运行 foreach
命令,那么我们需要生成一个字符串,该字符串被转义以供任何 POSIX-compliant 使用shell.
Bash 没有这样做的功能...但是 Python 有!
posix_escape() {
python3 -c 'import sys, shlex; print(" ".join([shlex.quote(s) for s in sys.argv[1:]]))' "$@"
}
git_foreach() {
local cmd_q
cmd_q=$(posix_escape "$@")
git submodule foreach "git $cmd_q ||:"
}