如何用单引号引用字符串?
例如,我可以这样做:
$ printf "%q\n" 'two words'
two\ words
$
有没有办法获得单(或双)引号字符串作为输出,即:
$ MAGIC 'two words'
'two words'
$
我发现单引号版本更容易阅读。
我想要一个适用于 {ba,z}sh 的答案。 POSIX shell 将是一个额外的好处。
答案1
假如说:
$ value=$'This isn\'t a \n\x1b "correct" test'
$ printf '%s\n' "$value"
This isn't a
"correct" test
POSIXquote () { printf %s\\n "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" ; }
使用:
$ quote "${value}"
'This isn'\''t a
"correct" test'
此函数只是将
'
字符串中的每个 « »(单引号)实例替换为 «'\''
»(单引号、反斜杠、单引号、单引号),然后在字符串的开头和结尾添加单引号。由于单引号内唯一含义特殊的字符是单引号字符本身,因此这是完全安全的。尾随换行符被正确处理,并且末尾的单引号兼作安全字符,以防止命令替换破坏尾随换行符,如果有人想做类似的事情:quoted=$(quote "$var")
警告:上面的 ESC(\033 或 \x1b 或十进制 27)字符(从技术上讲)被引用,但不可见。当发送到终端时,像其他控制字符一样,甚至可能造成伤害。只有当它们在视觉上呈现为$'\033'、$'\C-['或$'\E'时,它们才是清晰可见且明确的。
巴什printf '%s\n' "${value@Q}" $'This isn\'t a \n\E "correct" test'
桀骜printf '%s\n' ${(q)value} This\ isn\'t\ a\ $'\n'$'\033'\ \"correct\"\ test
桀骜printf '%s\n' ${(qq)value} 'This isn'\''t a "correct" test'
桀骜printf '%s\n' ${(qqq)value} "This isn't a \"correct\" test"
桀骜printf '%s\n' ${(qqqq)value} $'This isn\'t a \n\033 "correct" test'
桀骜printf '%s\n' ${(q-)value} 'This isn'\''t a "correct" test'
桀骜printf '%s\n' ${(q+)value} $'This isn\'t a \n\C-[ "correct" test'
小心一些 zsh 带引号的字符串:上面的 ESC(\033 或 \x1b 或十进制 27)字符全部(技术上)被带引号,但不可见。当发送到终端时,像其他控制字符一样,甚至可能造成伤害。只有当它们在视觉上呈现为$'\033'、$'\C-['或$'\E'时,它们才是清晰可见且明确的。
从Bash 的手册:
${parameter@operator}
Q
扩展是一个字符串,它是以可重复用作输入的格式引用的参数值。
来自zshexpn
手册页:
q
在结果单词中用反斜杠引用 shell 特有的字符;不可打印或无效的字符使用以下形式引用$'\NNN'
,每个八位字节都有单独的引号。如果此标志给出两次,则结果单词用单引号引起来;如果给出三次,则结果单词用双引号引起来;在这些形式中,不会尝试对不可打印或无效字符进行特殊处理。如果该标志出现四次,则单词会用单引号引起来,前面带有
$
。请注意,在所有这三种形式中,引用都是无条件完成的,即使这不会改变 shell 解释结果字符串的方式。如果
q-
给出了 a(只能出现一个q
),则使用单引号的最小形式,仅在需要保护特殊字符时才引用字符串。通常,这种形式提供最易读的输出。如果
q+
给出 a,则使用最小引用的扩展形式,这会导致使用 呈现不可打印的字符$'...'
。此引用类似于排版命令系列的值输出所使用的引用。
答案2
Zsh 有很多可以应用的引用选项参数扩展:
q
在结果单词中用反斜杠引用 shell 特有的字符;不可打印或无效的字符使用以下形式引用
$'\NNN'
,每个八位字节都有单独的引号。如果此标志给出两次,则结果单词用单引号引起来;如果给出三次,则结果单词用双引号引起来;在这些形式中,不会尝试对不可打印或无效字符进行特殊处理。如果该标志出现四次,则单词会用单引号引起来,前面带有
$
。请注意,在所有这三种形式中,引用都是无条件完成的,即使这不会改变 shell 解释结果字符串的方式。如果
q-
给出 a(只能出现一个 q),则使用单引号的最小形式,仅在需要保护特殊字符时才引用字符串。通常,这种形式提供最易读的输出。如果
q+
给出 a ,则使用最小引用的扩展形式,这会导致使用 呈现不可打印的字符$'...'
。此引用类似于排版命令系列的值输出所使用的引用。
所以像这样的函数:
MAGIC () {
printf "%s\n" "${(q+)@}"
}
会给出如下输出:
$ MAGIC 'two words'
'two words'
$ MAGIC 'two words "'
'two words "'
$ MAGIC 'two '"'"'words'
'two '\''words'
答案3
这是使用 sed 的一个相当简单的解决方案。输入为$raw
,输出为$quoted
。
quoted=$(printf '%sz\n' "$raw" | sed "s/'/'\\\\''/g; s/'''/'/g")
quoted="'${quoted%z}'"
的技巧z
是正确处理尾随换行符。使用 just printf %s "$raw"
,当输入不以换行符结尾时,您需要依赖 sed 的行为,然后命令替换始终会吃掉所有尾随换行符。
sed 脚本中的第二个替换不是必需的,但是当输入中''
有连续的 ' 时,它可以避免输出中的无用,从而产生稍微更好的输出。'
这是一个纯粹的 POSIX sh 解决方案(即使在本机模式下,它也可以在 zsh 中工作)。它还避免了无用的''
,但保留''
了空字符串。
tail=$raw
quoted=
sq=\'
while
case "$tail" in
'') false;;
\'*) quoted="$quoted\\'"; tail="${tail#?}";;
[!\']*\'*) quoted="$quoted'${tail%%$sq*}'\\'"; tail="${tail#*$sq}";;
*) quoted="$quoted'${tail%%$sq*}'"; false;;
esac
do
:
done
if [ -z "$quoted" ]; then quoted="''"; fi