1

After reading this SO post, which suggests removing "line breaks" (understood as \n not \r\n) in bash using "c-style strings" (e.g., ${COMMAND//[$'\t\r\n']}), why not use echo instead? In other words:

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

OR

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

Does this cause unintentional side-effects or other problems? If the requirement is to remove line breaks, it seems simpler than ${foo//[$'\n']}

Note: I'm aware that echo "$foo" retains the line breaks and that if foo contains \r\n then echo "$foo" won't display everything on a single line.

mellow-yellow
  • 1,670
  • 1
  • 18
  • 38
  • 2
    `echo` doesn't have a [standard behavior](https://unix.stackexchange.com/questions/219268/how-to-add-new-lines-when-using-echo#answer-219274) you can rely upon when it comes to handling of newline. The shell method is more definitive. – lurker Feb 28 '19 at 20:05
  • 2
    See the APPLICATION USAGE and RATIONALE sections of [the POSIX specification for `echo`](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html) to appreciate just how unreliable/nonportable its behavior *is*. Even `echo`'s own specification document suggests that `printf` be used instead. – Charles Duffy Feb 28 '19 at 20:48
  • 3
    [BashPitfalls #14](http://mywiki.wooledge.org/BashPitfalls#echo_.24foo) is also relevant. – Charles Duffy Feb 28 '19 at 20:51
  • Doing something like `tr '\n' ' ' <<< "$foo"` is only slightly longer, and without the nasty side effects. – Mike Holt Feb 28 '19 at 21:28

1 Answers1

5

Yes, echo $foo will cause unexpected side-effects.

Issues with pathname expansion

Consider a directory with these four files:

$ ls
f*  factor  fo?  foo

Now, observe that echo $foo produces a list of eight file names:

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

This is because the unquoted $foo in echo $foo is subjected not just to word splitting (which is what eliminates the newlines) but also to pathname expansion.

If we use pattern substitution inside double quotes, however, we get the correct file list:

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

Issues with bash's echo

As @lurker pointed out, echo can act in surprising ways.

Consider a directory with three files:

$ ls
-e  \none  \text

Now, try:

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

one     ext

As you can see, the file names were mangled. This is because echo interpreted the file name -e not as a file name but as an option, the one that turns on interpretation of escape sequences. Thus, the file name whose characters are backslash-n-o-n-e becomes newline-one. and the file name whose characters are backslash-t-e-x-t becomes tab-ext.

Bash's echo command is not compatible with POSIX's echo for which -e is treated as text to be printed. Thus code relying on echo is not portable. For this reason, among others, it is often recommended that new code use printf rather than echo.

John1024
  • 109,961
  • 14
  • 137
  • 171
  • 1
    ...moreover, even treating `-e` as something other than a string to be printed makes bash's `echo` noncompliant with the POSIX standard (albeit a noncompliant behavior that can be turned off by flipping appropriate runtime or compile-time flags), so even *that* can't be relied on. – Charles Duffy Feb 28 '19 at 20:47