Whenever im trying to insert output with a line break into a variable for instance like this:
Hello
World
Once i do an echo command on the variable i get this:
"Hello World"
Why does it happen and how can i
keep the line break?
In bash, the easiest way to express a literal line break is with $'' syntax:
var=$'Hello\nWorld'
echo "$var"
Note that the quotes around $var are mandatory during expansion if you want to preserve linebreaks or other whitespace! If you only run
echo $var
...then even though a linebreak is stored in your variable, you will see
Hello World
on a single line, as opposed to
Hello
World
on two lines.
This happens because when you don't use quotes, the shell splits the expanded words on whitespace -- including newlines -- and passes each item created by that split as a separate argument. Thus,
echo "$var"
will pass a single string with the entire expansion of $var, whereas
echo $var
will run the equivalent of:
echo "Hello" "World"
...passing each word in the text as a separate argument to echo (whereafter the echo command re-joins its arguments by spaces, resulting in the behavior described).
Line breaks can be embedded in a string in any POSIX compatible shell:
$ str="Hello
> World"
$ echo "$str"
Hello
World
If you hit enter before closing the quotation marks, the shell knows you have not yet finished the quoted material, and prints the secondary prompt (>) and waits for you to finish the command.
Related
Here is an example script I made to illustrate what I mean when I say that I'm having trouble understanding why echo does not print in new line when calling a method from within another method:
prints_new_lines(){
echo hello
echo hello2
echo $(does_not_print_new_lines)
}
does_not_print_new_lines(){
echo here
printf "\n"
echo here2
}
prints_new_lines
I added the printf "\n" to see if that would work...
If you want to print the newline, you need to do:
echo "$(does_not_print_new_lines)"
i.e. with quotes.
It has nothing to do with calling from within a function, and everything to do with quoting.
Explanation:
Without quotes, your echo command basically translates to:
echo here\
here2
i.e. the shell sees a single command, echo, with 2 arguments, here and here2, separated by some whitespace - newline in this case.
So it just calls
echo 'here' 'here2'
Which is why you don't see a newline.
But with quotes, the command translates to
echo "here\
here2"
i.e. the shell sees a single command, echo, with 1 argument:
here
here2
So it calls
echo 'here
here2'
And you get your newline.
FWIW you should probably just drop the echo and use
does_not_print_new_lines
instead.
In a Linux shell, I want to print:
$300
$400
But when I do echo -e "$300\n$400" it shows:
00
00
When I do printf "$300\n$400" it shows the same thing!
So why does shell delete my dollar sign and the number right after it? Is there a way to print what I want?
You need to escape dollar $, since you are using double quotes, This will ensure the word is not interpreted by the shell.
$ echo -e "\$300\n\$400"
$300
$400
You may be aware how to access variables,
Example :
$ test="foo"
$ echo "$test"
foo
Suppose if you want to print $test, then you have use either
$ echo "\$test"
$test
OR with single quotes
$ echo '$test'
$test
In the shell, the $ character has a special meaning. It means "replace the $ and the following word or digit or special character with the value of a variable of that name". For example:
currency='EUR'
echo "The currency is $currency"
The variables 0, 1, 2, etc. contain the command line arguments to the program. So if you run your program as my-program Hello, world, you can write this code:
echo "argument 1 is $1"
echo "argument 2 is $2"
echo "both together are $1 $2, and all arguments are $*"
To make the $ character lose this special meaning, it must be written as \$. For example:
price=123
echo "The price is $price\$"
The first $ refers to the variable, and the second $ is escaped.
Alternatively you can surround your string in 'single quotes', which removes the special meaning of all characters.
To learn more about this topic, run the man bash command and read the section about variable expansion.
$ has special meaning to the shell; when it sees a $, it expects an existing shell variable name to follow. For example, $PATH.
In your case, you don't want the shell to think that you're trying to print out the value of shell variables, so you must tell the shell that the $ is indeed what you want to be displayed. This is done by preceding it with a backslash as explained in other answers.
Adding a backslash before characters is called escaping them (yes, not the most obvious terminology), and you are already using some escape characters unknowingly. (\n)
This applies to display other operators too, such as =, :, etc. Hope that helps.
You can use single quote. Enclosing characters in single-quotes (') shall preserve the literal value of each character within the single-quotes, where as enclosing characters in double-quotes(") shall preserve the literal value of all characters within the double-quotes, with the exception of the characters back quote, dollar-sign, and backslash.
echo -e '$'300"\n"'$'400
I "inherited" some code in a project, and in one of the Bash scripts, they use echo on a backticks-row, like:
#!/bin/bash
echo `/path/command argument`
What's the difference between that and just running the command itself?
#!/bin/bash
/path/command argument
Both send the command's output to the script's stdout.
So what's the difference? Why use echo?
To combine it with a > seems even worse:
#!/bin/bash
echo `/path/command argument > /var/log/exemple.log`
It doesn't look particularly useful in its current form but one side-effect of using echo with (unquoted) backticks is that whitespace between words is lost. This is because of word splitting - every word in the output of the command is treated as a separate argument to echo, which just outputs them separated by a single space. For example:
$ echo "a b c"
a b c
$ echo `echo "a b c"`
a b c
Note that this applies to all types of whitespace such as tab characters and newlines.
I'm not sure why you'd want to do this deliberately! Personally, I'd be tempted to just run the command normally.
I "inherited" some code in a project, and in one of the Bash scripts, they use echo on a backticks-row, like:
#!/bin/bash
echo `/path/command argument`
What's the difference between that and just running the command itself?
#!/bin/bash
/path/command argument
Both send the command's output to the script's stdout.
So what's the difference? Why use echo?
To combine it with a > seems even worse:
#!/bin/bash
echo `/path/command argument > /var/log/exemple.log`
It doesn't look particularly useful in its current form but one side-effect of using echo with (unquoted) backticks is that whitespace between words is lost. This is because of word splitting - every word in the output of the command is treated as a separate argument to echo, which just outputs them separated by a single space. For example:
$ echo "a b c"
a b c
$ echo `echo "a b c"`
a b c
Note that this applies to all types of whitespace such as tab characters and newlines.
I'm not sure why you'd want to do this deliberately! Personally, I'd be tempted to just run the command normally.
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)?
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:
echo $x
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:
echo "$x"
With that single change, the output of your script becomes:
$ bash a,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 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:
printf "Hello\nworld"
echo $'hello\nworld'
The printf does not print a newline after world. Hence, that world appears on the same line as the hello which follows.
Documentation of the Details
man bash explains that double-quotes inhibit word splitting:
If the substitution appears within double quotes, word splitting and pathname expansion are not performed on the results.
Word-splitting happens after variable expansion, command
substitution, and arithmetic expansion:
The shell scans the results of parameter expansion, command
substitution, and arithmetic expansion that did not occur within
double quotes for word splitting.
Another subtlety is that word splitting is performed only if some substitution took place:
Note that if no expansion occurs, no splitting is performed.
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:
The shell treats each character of IFS as a delimiter, and splits the
results of the other expansions into words on these characters. If
IFS is unset, or its value is exactly , the
default, then sequences of space, tab, and newline at the
beginning and end of the results of the previous expansions are
ignored, and any sequence of IFS characters not at the beginning or
end serves to delimit words. If IFS has a value other than the
default, then sequences of the whitespace characters space and tab are
ignored at the beginning and end of the word, as long as
the whitespace character is in the value of IFS (an IFS whitespace
character). Any character in IFS that is not IFS whitespace, along
with any adjacent IFS whitespace characters, delimits a field. A
sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.
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 by PS4 (default is +, space) to distinguish it from normal output.
The debug output can be turned off by including the line set +x.
set -x and set +x both also work on the command line.
Use stderr
Send debug output to stderr (file descriptor 2) as follows:
echo "My Debug Info" >&2
By default, pipelines and command substitutions only operate on stderr. Consequently, information sent to stderr 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 an n:
$ echo "Hello\nworld 4"
Hello\nworld 4
To have \n interpreted as a newline, use -e:
$ echo -e "Hello\nworld 4"
Hello
world 4
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):
#!/bin/bash
a_function() {
echo -e "Hello\nworld\n 1"
echo "Hello"
echo "world"
echo "Hello\nworld 4"
}
echo -e "Hello\nworld\n 1"
echo "Hello"
echo "world"
echo "Hello\nworld 4"
x=$(a_function "x")
echo "x-no-quotes>"
echo $x # No new lines!
echo "<x-no-quotes"
echo "x-in-double-quotes>"
echo "$x" # Yes new lines!
echo "<x-in-double-quotes"
echo -e "Hello\nworld\n 1"
echo "Hello"
echo "world"
echo "Hello\nworld 4"
Output:
Hello
world
1
Hello
world
Hello\nworld 4
x-no-quotes>
Hello world 1 Hello world Hello\nworld 4
<x-no-quotes
x-in-double-quotes>
Hello
world
1
Hello
world
Hello\nworld 4
<x-in-double-quotes
Hello
world
1
Hello
world
Hello\nworld 4
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 quote:
echo '$x'