I have multiple Bash variables for ANSI terminal colors. One is ANSI_NOCOLOR and defined as this:
ANSI_NOCOLOR="\e[0m"
When I use it togather with a backslash character \ (escaped as \\ in Bash strings), I get an unexpected output.
Example:
echo -e "command --with --many --options \\$ANSI_NOCOLOR"
echo -e "--more --options"
This results in:
command --with --many --options \e[0m
--more --options
This example can be reduced to:
$ echo -e "\\\e[0m"
\e[0m
Why is a tripple backslash in Bash not acting as normally known from other C-like languages?
Expected / C-like behavior:
Escape sequences are left-associative. Thus,
the first two \\ are printed as \,
the remaining \ is doing a look-ahead(1) to find e for creating the ESC character.
Workaround:
After some planing with backslashes, I found, that 5 !! backslashes are required. I still would like to read an explanation, why it behaves as it is.
$ echo -e "\\\\\e[33mfoo\e[0m"
\foo
It's hard to control a color-reset sequence, so my workaround uses two ANSI color escape sequences, to set it to yellow and back to default.
This happens because there are two levels of escaping at work:
escaping for the double quoted string. This pass recognizes \\ but not \e
echo -e escape sequences. This pass recognizes both \\ and \e.
So:
The initial string is \\\e
The double quotes replace the \\ but leaves the unsupported \e alone
You now have \\e
Echo replaces the \\
You now have \e
This is one of the many reasons why you should prefer printf over echo whenever any value may contain a backslash.
Related
I am running these two commands in Git bash.
Why they behave differently? Aren't they supposed to do the same thing or am I missing something?
git diff > D:\Patches\afterWGComment.txt
creates file PatchesafterWGComment.txt in D:/
git diff > D:/Patches/afterWGComment.txt
correctly creates file afterWGComment.txt in D:/Patches/
Note that D:/Patches/ folder is present before running the above commands.
Bash treats backslash as an escape character, meaning that the symbol following it is interpreted literally, and the backslash itself is dropped.
$ echo $HOME
/home/user
$ echo \$HOME
$HOME
Under Windows, where backslash serves as a path separator, this causes some inconvenience. Fortunately, inside single quotes a backslash character loses its special meaning and is treated literally (as any other character, except a single quote):
$ echo '\$HOME'
\$HOME
Therefore, if you are going to copy&paste a Windows path into Git bash, put it inside single quotes:
git diff > 'D:\Patches\afterWGComment.txt'
Backslash is an escape character used to escape meta characters. This means you need to escape the escape:
D:\\Patches\\afterWGComment.txt
Alternative you can put your string in single quotes, which will make all characters literal:
'D\Patches\afterWGComment.txt'
Some meta characters: *, ~, $, !, ...
Well the Backslash (\) in Linux generally means a escape character. So in your case the backslash is escaping strings. Try with a cd "D:\Patches\afterWGComment.txt" and you can see the difference.
The back slash has a very long history in Unix (and therefore in Linux) of meanning: quote next character.
There are three ways to quote in the shell (where you type commands):
The backquote (\)
Single quotes (')
Double quotes (")
In the order from stronger to softer. For example, a $ is an special character in the shell, this will print the value of a variable:
$ a=Hello
$ echo $a
Hello
But this will not:
$ echo \$a
$a
$ echo '$a'
$a
$ echo "$a"
Hello
In most cases, a backslash will make the next character "not special", and usually will convert to the same character:
$ echo \a
a
Windows decided to use \ to mean as the same as the character / means in Unix file paths.
To write a path in any Unix like shell with backslashes, you need to quote them:
$ echo \\
\
$ echo '\'
\
$ echo "\\"
\
For the example you present, just quote the path:
$ echo "Hello" > D:\\Patches\\afterWGComment.txt
That will create the file afterWGComment.txt that contains the word Hello.
Or:
$ echo "Hello" > 'D:\Patches\afterWGComment.txt'
$ echo "Hello" > "D:\\Patches\\afterWGComment.txt"
$ echo "Hello" > "D:/Patches/afterWGComment.txt"
Quoting is not simple, it has adquired a long list of details since the 1660's.
I have a project with the goal of implementing the same behavior as the echo command. My problem is with backslashes. My information says that when a backslash appears you must considering the next character as a simple character, but here I guess it's not the same.
This an example :
echo \\\\
OUTPUT : \
The problem here is that I expect that the output to be 2 backslashes, not just one.
To get 2 backslashes I need to write 6 backslashes:
echo \\\\\\
Can anyone help me to understand this behavior?
There are multiple layers where the backslashes are interpreted. It is an escape character in the shell(among other places). A backslash followed by a character is an escape code for another character(for instance, \n is interpreted as a line break).
When you first execute echo \\\\\\, the shell parses the escape sequences and ends up passing \\\ to the command(in this case echo).
Quoting the string on the shell will prevent interpretation there(i.e. echo "\\" will literally pass two backslashes to the echo command). You also either have an additional layer of interpretation or your program is incorrectly handling the backslash sequence. Ultimately, you'll need to escape it for each layer.
So to write a backslash to stdout you do
zsh$ echo \\
\
You would think that to output 2 backslashes, you need to run this:
zsh$ echo \\\\
\
Wrong, You need 6 or 8:
zsh$ echo \\\\\\
\\
zsh$ echo \\\\\\\\
\\
Why on earth would I need 8 backslashes ?
Behaviors in different shells :
ksh$ echo \\\\
\\
zsh$ echo \\\\
\
bash$ echo \\\\
\\
sh$ echo \\\\
\
csh$ echo \\\\
\\
You are probably used to bash's built-in echo, which does not perform expansion of escape sequences. POSIX echo, however, does. zsh follows the POSIX specification, so when you write echo \\\\\\, here's what happens.
Quote removal reduces \\\\\\ to \\\; each escaped \ becomes a literal \.
echo takes the three \ it receives, and replaces the first \\ with \. The remaining \ doesn't precede anything, so it is treated literally.
The final result is an output of two \.
With echo \\\\\\\\, here's what happens.
As before, \\\\\\\\ becomes \\\\, because each pair of backslashes becomes a single \ after quote removal.
echo takes the 4 backslashes, and replaces the first \\ with \ and the second \\ with \ as well, since this time it received two matched pairs.
The final result is again two \.
bash probably inherited its non-POSIX comformance from ksh, sh is by definition a POSIX-comformant shell, and it's best not to think about what csh is doing.
Not only zsh, it's default behavior in terminal, backslash (\) is a special character used to tell bash script that you want to other params/texts in newline, so to avoid newline,u need add another backslash to escape special character, since backslash also used for escape special character
when I assign like this:
rmall="\,\.\?\!\:\;\(\)\[\]\{\}\"\'"
then echo $rmall, I got this:
\,\.\?\!\:\;\(\)\[\]\{\}\"\'
But what I want is only , How can I do?
,.?!:;()[]{}"'
as later I need to remove those.
Thank you
You are double quoting by using quotes and backslashes. Use one or the other.
Note: You will always need to use backslash for escaping your quote character but otherwise not needed.
Inside double quotes, only three escape sequences are treated specially:
\" is replaced by a literal "
\$ is replaced by a literal $
\\ is replaced by a literal \
These three are required to allow the literal character in contexts where they would normally produce special behavior. \", obviously, lets you include a double-quote inside a double-quoted string. \$ lets you output a literal dollar sign where it would otherwise trigger parameter substitution:
bash $ foo=5; echo "\$foo = $foo"
$foo = 5
\\ lets you output a literal backslash that precedes a parameter substitution or at the end of a string.
bash $ foo=5; echo "\\$foo"
\5
bash $ echo "Use a \\"
Use a \
A backslash followed by any other character is treated literally:
bash $ echo "\x"
\x
Should I double quote or escape with \ special characters like ',
$ echo "'"
'
$ echo \'
'
Here is apparently doesn't matter, but are there situations where there is a difference, except for $, `` or`, when I know there is a difference.
Thanks,
Eric J.
You can use either backslashes, single quotes, or (on occasion) double quotes.
Single quotes suppress the replacement of environment variables, and all special character expansions. However, a single quote character cannot be inside single quotes -- even when preceded by a backslash. You can include double quotes:
$ echo -e 'The variable is called "$FOO".'
The variable is called "$FOO".
Double quotes hide the glob expansion characters from the shell (* and ?), but it will interpolate shell variables. If you use echo -e or set shopt -s xpg_echo, the double quotes will allow the interpolation of backslash-escaped character sequences such as \a, and \t. To escape those, you have to backslash-escape the backslash:
$ echo -e "The \\t character sequence represents a tab character."
The \t character sequence represents a tab character."
The backslash character will prevent the expansion of special characters including double quotes and the $ sign:
$ echo -e "The variable is called \"\$FOO\"."
The variable is called "$FOO".
So, which one to choose? Which everyone looks the best. For example, in the preceding echo command, I would have been better off using single quotes and that way I wouldn't have the confusing array of backslashes one right after another.
On the other hand:
$ echo -e "The value of \$FOO is '$FOO'."
The value of FOO is 'bar'.
is probably better than trying something like this:
$ echo -e 'The value of $FOO is '"'$FOO'."
Readability should be the key.