Bash中等价于Python的shlex.quote

4
Python标准库中有一个名为shlex.quote的函数,它接受一个字符串并返回一个可以被Unix shell解释为同一字符串的字符串。这是通过将字符串放在单引号中并转义其中出现的任何单引号字符来实现的。
当您模板化shell脚本并不能保证替换的值仅包含“shell安全”的字符串时,此功能非常有用。
我的问题是:是否存在纯bash编写的等效机制,最多依赖于coreutils?或者甚至是我不知道的bash内置机制?
下面是一个使用此类实用程序(此处称为shlex_quote)的最小示例: generate_greeting_script.sh:
#!/bin/bash
cat > greet.sh <<HEREDOC
#!/bin/bash
greeting=$(shlex_quote "$1")
echo "\$greeting \$(whoami)!"
HEREDOC
chmod +x greet.sh

$ ./generate_greeting_script.sh "'ello"
$ ./greet.sh
'ello govnah!

可以使用Python 的 shlex.quoteshlex_quote 工具来解决这个问题,但仅为此目的而依赖于Python 是过度杀伤力的。

4个回答

4

既然您提到了bash,就可以在printf中使用bash特定的格式字符“q”:

$ printf '%q\n' "The world is fuiled by \$s isn't it?" 
The\ world\ is\ fuiled\ by\ \$s\ isn\'t\ it\?

来自bash的文档:

%q
使printf以可以重用为shell输入的格式输出相应参数。

https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html


3

或使用@Q变量扩展

cat generate_greeting_script

#!/usr/bin/env bash

cat >greet <<HEREDOC
#!/usr/bin/env bash

printf ${1@Q}' %s!\n' "\$USER"
HEREDOC
chmod +x greet

./generate_greeting_script 'I say hello to'
.sh扩展名并不是在带有shebang的可执行脚本中所必需的。

生成的greet

#!/usr/bin/env bash

printf 'I say hello to'' %s!\n' "$USER"

输出:

./greet
I say hello to lea!

参考 man bash:

${parameter@operator}

参数变换。

这种扩展要么是参数值的转换,要么是关于参数本身的信息,具体取决于操作符的值。每个操作符都是一个单字母:

Q

扩展是一个字符串,该字符串是参数值以格式引用的形式,可作为输入重复使用。


对我来说,那似乎是最符合惯用法的答案(并且比基于 printf %q 的答案稍微短一些)。有趣的是,printf %q${...@Q} 使用不同的方法来执行引号的精确引用:使用 printf 时,'ello there 变成了 \'ello\ there,而使用 Q 转换则变成了 ''\''ello there'。我猜如果有很多引号,printf 的表示更加“高效”,而如果有很多空格,则 @Q 更好。 - smheidrich
“@Q” 是什么时候添加的?我想大约是在4.x左右?在干净的MacOS上使用bash 3.2,我很少使用它 :-) - Andreas Louv
@AndreasLouv 如果你经常使用Bash,那么升级到Bash 5.1或5.2是值得的。Bash 3.2是2006年的版本(已经15年了,在计算机领域几乎可以称之为过时)。 - Léa Gris

2
我认为您正在寻找特定于Bash的printf格式说明符%q
$ read &&  printf "%q\n" "$REPLY"
"very*complicated_&&;$stuff--string'""""'"<<!!
\"very\*complicated_\&\&\;\$stuff--string\'\"\"\"\"\'\"\<\<\!\!
$ echo \"very\*complicated_\&\&\;\$stuff--string\'\"\"\"\"\'\"\<\<\!\!
"very*complicated_&&;$stuff--string'""""'"<<!!

1

$1的引用内容放入变量greeting中:

printf -v greeting '%q' "$1"

那使用了Bash特定的-v选项和%q格式字符串来进行printf操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接