【问题标题】:In bash, why not remove line breaks using echo?在 bash 中,为什么不使用 echo 删除换行符?
【发布时间】:2019-02-28 19:57:52
【问题描述】:

阅读this SO post 后,建议使用“c 样式字符串”(例如,${COMMAND//[$'\t\ r\n']}),为什么不使用echo呢?换句话说:

foo=$'Apple\nBanana\nCherry\n'
echo $foo
Apple Banana Cherry

foo=$(ls -1)
echo $foo
Jenkinsfile README.md exclude_contents install_kit.sh packaging

这会导致意外的副作用或其他问题吗?如果要求是去掉换行符,似乎比${foo//[$'\n']}简单

注意:我知道echo "$foo" 保留换行符,如果foo 包含\r\n,那么echo "$foo" 不会在一行中显示所有内容。

【问题讨论】:

  • echo 没有 standard behavior 在处理换行时可以依赖。 shell方法更确定。
  • 查看the POSIX specification for echo 的应用程序用法和基本原理部分,了解其行为是多么不可靠/不可移植。甚至echo 自己的规范文档也建议改用printf
  • BashPitfalls #14 也是相关的。
  • tr '\n' ' ' <<< "$foo" 这样的操作只会稍微长一点,而且没有讨厌的副作用。

标签: bash echo


【解决方案1】:

是的,echo $foo 会导致意想不到的副作用。

路径名扩展问题

考虑一个包含这四个文件的目录:

$ ls
f*  factor  fo?  foo

现在,观察echo $foo 生成一个包含八个文件名的列表:

$ foo=$(ls -1)
$ echo $foo
f* factor fo? foo factor fo? foo foo

这是因为echo $foo 中未引​​用的$foo 不仅受到分词(消除换行符)的影响,还受到路径名扩展的影响。

如果我们在双引号内使用模式替换,我们会得到正确的文件列表:

$ echo "${foo//$'\n'/ }"
f* factor fo? foo

bash 的回声问题

正如@lurker 指出的那样,echo 可以以令人惊讶的方式行事。

考虑一个包含三个文件的目录:

$ ls
-e  \none  \text

现在,试试:

$ foo=$(ls -1)
$ echo $foo

one     ext

如您所见,文件名已损坏。这是因为echo 将文件名-e 解释为不是文件名,而是作为一个选项,即打开转义序列解释的选项。因此,字符为反斜杠-n-o-n-e 的文件名变为换行符。并且字符为反斜杠-t-e-x-t的文件名变为tab-ext。

Bash 的 echo 命令与 POSIX's echo 不兼容,-e 被视为要打印的文本。因此依赖echo 的代码是不可移植的。出于这个原因,其中通常是recommended 新代码使用printf 而不是echo

【讨论】:

  • ...此外,即使将 -e 视为要打印的字符串以外的其他内容,也会使 bash 的 echo 不符合 POSIX 标准(尽管可以通过翻转适当的操作来关闭不符合要求的行为)运行时或编译时标志),因此即使 也不能依赖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2020-11-02
  • 2015-07-22
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
相关资源
最近更新 更多