如何在命令替换期间禁用分词?

如何在命令替换期间禁用分词?

如何在命令替换期间禁用分词?这是问题的一个简化示例:

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 版本的echodo。

$ 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)"

相关内容