I'm in a bash crash course today.
This is a bash function that returns a value, via echo:
#!/bin/bash
get_hello_name() {
echo 'Hello $1!'
}
msg=$(get_hello_name "x")
echo $msg
Output:
$ bash ./initial_script5.sh
Hello $1!
I then incorrectly thought that the last echo was returned (I come from Java and Python), and was trying to use echo to debug the rest of the function.
And then I was wondering why the heck I could not print out newlines in my echo statements, despite trying every single suggestion in this question.
This script demonstrates the problem:
#!/bin/bash
a_function() {
echo "---In function"
printf %"s\n" hello world
printf "Hello\nworld"
echo $'hello\nworld'
echo -e 'hello\nworld'
}
echo "---Pre function"
printf %"s\n" hello world
printf "Hello\nworld"
echo $'hello\nworld'
echo -e 'hello\nworld'
x=$(a_function "x")
echo $x
echo "---Post function"
printf %"s\n" hello world
printf "Hello\nworld"
echo $'hello\nworld'
echo -e 'hello\nworld'
$ bash ./initial_script5.sh
---Pre function
hello
world
Hello
worldhello
world
hello
world
---In function hello world Hello worldhello world hello world
---Post function
hello
world
Hello
worldhello
world
hello
world
The problem is that all of the echos in the function are concatenated together, after being individually trimmed, and then returned as a whole.
So this leads me to two questions: How do you debug a function that returns a value, and how do you append newlines onto a variable (not that I even want to do the latter, necessarily, but I would like to understand it)?
You might want to call it with a double quote
echo "$x"
However if you would want to explicitly show what you typed inside, also known as literal expression use a single quoteecho '$x'
The working code after following John1024's tips (note the newlines print in the "1" lines, but not the "4", because of the
e
option):Output:
Why the newlines seemed to disappear from the variable
The newlines are actually retained in the variable. They do not display because the variable in the
echo
statement is not enclosed in double-quotes. From the code:When using a variable without double-quotes, word splitting is performed. Under the default
$IFS
(wiki entry on IFS), this means that all collections of whitespace, including newlines and tabs, are replaced with single space.To avoid that, simply use double quotes as in:
With that single change, the output of your script becomes:
The newlines that were always in the variable
x
are now displayed.Aside: the two words that remain strung together
Note that the combination
worldhello
appears on one line because because that is what the code asked for:The
printf
does not print a newline afterworld
. Hence, thatworld
appears on the same line as thehello
which follows.Documentation of the Details
man bash
explains that double-quotes inhibit word splitting:Word-splitting happens after variable expansion, command substitution, and arithmetic expansion:
Another subtlety is that word splitting is performed only if some substitution took place:
Normally, when word splitting is performed, all strings of spaces, tabs, and newlines are replaced by a single space. This default behavior can be changed by changing the value of the
IFS
variable:How to Debug
Use
set -x
Place the line
set -x
at the beginning of the code that you wish to run. The results of evaluating each line will be displayed as the function is run, each preceded byPS4
(default is+
, space) to distinguish it from normal output.The debug output can be turned off by including the line
set +x
.set -x
andset +x
both also work on the command line.Use
stderr
Send debug output to
stderr
(file descriptor 2) as follows:By default, pipelines and command substitutions only operate on
stderr
. Consequently, information sent tostderr
will, by default, appear on the terminal.More on
echo
By default,
echo
ignores escape characters and the sequence\n
simply means a\
followed by ann
:To have
\n
interpreted as a newline, use-e
: