zsh 的 `print -P` 的转义变量

zsh 的 `print -P` 的转义变量

我正在寻找一种方法来转义包含格式说明符和特殊字符(例如引号、反斜杠和换行符)的变量,以便在将其传递给print -P它时会按字面意思打印出来。

所以本质上我希望这两个打印相同的:

> cat file.txt
> my_var="$(cat file.txt)"
> print -P "${<magic>my_var}"

我使用的测试用例的一个很好的示例文件是这样的:

Backslash \
Double Backslash \\

Single Quote '
Double Quote "

-----------------------
Escaped Linebreak \n
-----------------------

Color codes: %F{red}not red%f

Variable expansion $SHELL

我得到的最接近的是${${(q+)my_var}//\%/%%}引号、换行符、反斜杠和变量扩展的问题:

$'Backslash Double Backslash \

Single Quote '
Double Quote "

-----------------------
Escaped Linebreak \n
-----------------------

Color codes: %F{red}not red%f

Variable expansion /usr/bin/zsh'

我知道printf '%s\n' "$my_var"。然而在实践中,变量周围有很多实际的格式化print -P,所以这对我来说没有用。遗憾的是print -P,在变量周围和实际变量中使用printf也不起作用,因为在某些情况下,字符串操作会应用于变量的内容。

答案1

${(q)…}及其变体使用'…',"…"$'…'引号,但print -P不进行任何引号扩展,仅进行反斜杠扩展和提示扩展(这是百分比转义扩展,如果prompt_subst启用则加上替换)。所以我认为${(q)…}这里没有帮助。

禁用后prompt_subst,您需要保护反斜杠和百分号。启用后prompt_subst,您还需要保护美元和反引号。

if [[ -o prompt_subst ]]; then
  print -P -- "${${${${my_var//\\/\\\\\\\\}//\%/%%}//\$/\\\\\$}//\`/\\\\\`}"
else
  print -P -- "${${my_var//\\/\\\\}//\%/%%}"
fi

答案2

如果目的是打印一些字符串,其中一部分必须进行迅速扩展,或者\x部分不进行扩展,而不是执行以下操作:

print -P -- $string_to_undergo_both \
            ${string_to_undergo_prompt//\\/\\\\} \
            ${string_to_undergo_backslash//complex-brittle-expression} \
            ${string_to_undergo_none//complex-brittle-expression} \

你可以将其分解为:

print  -P -n -- $string_to_undergo_both' '
print -rP -n -- $string_to_undergo_prompt' '
print     -n -- $string_to_undergo_backslash' '
print -r     -- $string_to_undergo_none

(请注意print -rP,如果promptsubst启用该选项,则 with\仍然很特殊,因为它用于转义$,`及其本身,因此print -rP '\\'将输出\而不是\\)。

或者调用print -r --它打印raw(为了与 Korn shell 兼容而禁用\x默认打开的扩展print),但使用参数扩展标志在需要时启用提示扩展或反斜杠扩展:

print -r -- ${(g[o]%)string_to_undergo_both} \
            ${(%)string_to_undergo_prompt} \
            ${(g[o])string_to_undergo_backslash} \
            $string_to_undergo_none

${(flags):-literal-text}您还可以通过使用(${(%):-%F{red}}例如用于提示扩展)或$'...'用于反斜杠扩展的引号形式来为文字文本(不在变量中)启用这些。

另请参阅%%参数扩展标志以了解完整的提示扩展(包括启用时危险的应用promptsubst),以及e执行参数扩展、命令替换和算术扩展。

对于printf,反斜杠扩展在格式参数和格式指令的参数中执行%b(但对于后者的样式echo,而不是正常的 C 样式)。但没有用于提示扩展的格式指令。

然而,通过提示扩展,您还可以通过数组传递逐字文本(尽管要注意不可打印的字符,例如控制字符,会被转换为某种视觉表示形式(例如\n换行符、^[ESC、 U+FFFE) 。\ufffe$psvar

$ psvar=( '\\' %% )
$ print -P 'first is %F{red}%1v%f, second is %F{green}%2v%f'
first is \\, second is %%

因此,您可以使用以下命令来启用提示扩展printf

pprintf() {
  local psvar=("${(@)argv[2,-1]}")
  print -P -- "$1"
}
$ pprintf 'cwd: %~, host: %m, arbitrary printable string: "%1v"' '\\%%'
cwd: ~, host: myhost, arbitrary printable string: "\\%%"

(这里还进行反斜杠扩展,添加-r以禁用它)。

相关内容