如何在命令替换期间禁用分词?这是问题的一个简化示例:
4:00PM /用户/paymahn/下载 ❯❯❯猫测试.txt 你好\n世界 4:00PM /用户/paymahn/下载 ❯❯❯ echo $(cat test.txt) 你好 世界 4:00PM /用户/paymahn/下载 ❯❯❯ echo "$(cat test.txt)" 你好 世界 4:01PM /用户/paymahn/下载 ❯❯❯ echo "$(cat "test.txt" )" 你好 世界
我想要的是echo $(cat test.txt)
(或包括命令替换的某些变体)输出hello\nworld
.
我发现https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html它在底部说If the substitution appears within double quotes, word splitting and filename expansion are not performed on the results.
,但我似乎无法理解这一点。我本以为我已经尝试过的示例之一符合该规则,但我想并非如此。
答案1
将文字\n
更改为换行符不是关于分词,而是echo
处理反斜杠。有些版本echo
会这样做,有些则不会... Bashecho
默认情况下不处理反斜杠转义(没有-e
标志或xpg_echo
选项),但例如 dash 和 Zsh 版本的echo
do。
$ cat test.txt
hello\nworld
$ bash -c 'echo "$(cat test.txt)"'
hello\nworld
$ zsh -c 'echo "$(cat test.txt)"'
hello
world
改用printf
:
$ bash -c 'printf "%s\n" "$(cat test.txt)"'
hello\nworld
$ zsh -c 'printf "%s\n" "$(cat test.txt)"'
hello\nworld
也可以看看:为什么 printf 比 echo 更好?
不管怎样,您应该在命令替换周围加上引号,以防止在类似 sh 的 shell 中出现分词和通配符。 (除了 sh 模式外,zsh 仅在命令替换时(不在参数或算术扩展时)进行分词(而不是通配符)。)
答案2
zsh 实现的 echo 默认解释转义序列。最简单的解决方案是:
$ echo -E "$(cat test.txt)"
hello\nworld
或者
$ print -r "$(cat test.txt)"
正确的解决方案是使用 printf:
$ printf '%s\n' "$(<test.txt)"