我正在寻找一种方法来转义包含格式说明符和特殊字符(例如引号、反斜杠和换行符)的变量,以便在将其传递给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 --
它打印r
aw(为了与 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
以禁用它)。