shell:用单引号而不是反斜杠引用字符串

shell:用单引号而不是反斜杠引用字符串

如何用单引号引用字符串?

例如,我可以这样做:

$ 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

quote () { printf %s\\n "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" ; }

使用:

$ quote "${value}"
'This isn'\''t a
"correct" test'

Rich 的 sh posix 技巧

此函数只是将'字符串中的每个 « »(单引号)实例替换为 « '\''»(单引号、反斜杠、单引号、单引号),然后在字符串的开头和结尾添加单引号。由于单引号内唯一含义特殊的字符是单引号字符本身,因此这是完全安全的。尾随换行符被正确处理,并且末尾的单引号兼作安全字符,以防止命令替换破坏尾随换行符,如果有人想做类似的事情:

 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

相关内容