如何在 shell 中反转 `printf %q`?
How can `printf %q` be reversed in a shell?
命令 printf %q
(来自 GNU coreutils 或 bash)可用于引用一组参数,包括空格、换行符和引号。例如:
$ main() { printf '%q ' "${@}"; } && main "'a'" '"b"' 'c d' $'e\nf'
\'a\' \"b\" c\ d $'e\nf'
是否可以反转此操作,即从 printf %q
创建的字符串创建参数数组
- 在 POSIX shell?
- 在Bash?
- 使用其他工具?
这个问题的用例
“参数提供者”使用 printf %q "${@}"
将参数列表包装在单个字符串中。参数可以包含任意内容,包括但不限于:引号、带换行符的引号字符串、由 printf %q
创建的字符串。应使用 shell 脚本将字符串解包到参数数组中。展开应避免 eval
和未加引号的变量。该字符串可以作为命令行参数或通过 stdout/stdin.
传递
见解
xargs
不处理引用的换行符。
zsh
can do this 对于存储在变量 args
中的字符串:"${(Q@)${(z)args}}"
main() { printf '%q ' "${@}"; }
quoted=$(main "'a'" '"b"' 'c d' $'e\nf')
In a POSIX shell?
真的很简单。使用以下命令重新设置位置参数:
eval "set $quoted"
In Bash?
请参阅 Glenn 对 declare 的回答。
Using additional tools?
或者编写一个字符串解析器,输出“安全”正确引用的字符串,以 eval
为来源。就像 GNU getopt
所做的那样。在 POSIX 兼容的 shell 中这样做将是一个挑战,在 POSIX C 中可能会导致错误,在 python 和 shlex
中这样做可能是微不足道的。
使用declare
:
quoted=$(main "'a'" '"b"' 'c d' $'e\nf')
declare -a "myvar=($quoted)"
declare -p myvar
产出
declare -a myvar=([0]="'a'" [1]="\"b\"" [2]="c d" [3]=$'e\nf')
这不能用于计算命令:
$ declare -a "myvar=($(main ls -l sensitive files))"
$ declare -p myvar
declare -a myvar=([0]="ls" [1]="-l" [2]="sensitive" [3]="files")
需要注意的一件事:如果您在函数中使用 declare
,变量将成为该函数的 local(除非您在其中使用 declare -g
如果它是全球性的)
命令 printf %q
(来自 GNU coreutils 或 bash)可用于引用一组参数,包括空格、换行符和引号。例如:
$ main() { printf '%q ' "${@}"; } && main "'a'" '"b"' 'c d' $'e\nf'
\'a\' \"b\" c\ d $'e\nf'
是否可以反转此操作,即从 printf %q
- 在 POSIX shell?
- 在Bash?
- 使用其他工具?
这个问题的用例
“参数提供者”使用 printf %q "${@}"
将参数列表包装在单个字符串中。参数可以包含任意内容,包括但不限于:引号、带换行符的引号字符串、由 printf %q
创建的字符串。应使用 shell 脚本将字符串解包到参数数组中。展开应避免 eval
和未加引号的变量。该字符串可以作为命令行参数或通过 stdout/stdin.
见解
xargs
不处理引用的换行符。zsh
can do this 对于存储在变量args
中的字符串:"${(Q@)${(z)args}}"
main() { printf '%q ' "${@}"; }
quoted=$(main "'a'" '"b"' 'c d' $'e\nf')
In a POSIX shell?
真的很简单。使用以下命令重新设置位置参数:
eval "set $quoted"
In Bash?
请参阅 Glenn 对 declare 的回答。
Using additional tools?
或者编写一个字符串解析器,输出“安全”正确引用的字符串,以 eval
为来源。就像 GNU getopt
所做的那样。在 POSIX 兼容的 shell 中这样做将是一个挑战,在 POSIX C 中可能会导致错误,在 python 和 shlex
中这样做可能是微不足道的。
使用declare
:
quoted=$(main "'a'" '"b"' 'c d' $'e\nf')
declare -a "myvar=($quoted)"
declare -p myvar
产出
declare -a myvar=([0]="'a'" [1]="\"b\"" [2]="c d" [3]=$'e\nf')
这不能用于计算命令:
$ declare -a "myvar=($(main ls -l sensitive files))"
$ declare -p myvar
declare -a myvar=([0]="ls" [1]="-l" [2]="sensitive" [3]="files")
需要注意的一件事:如果您在函数中使用 declare
,变量将成为该函数的 local(除非您在其中使用 declare -g
如果它是全球性的)