BASH - Escape three backslash - bash

I want to display three backslashes in bash. I tried the codes below:
myString='\\\hello world'
echo ${myString} # output is '\\hello world'
I'm planning to put all kinds of special characters in the string. My question is how to treat it like a string and not escape any characters. Thanks!

Your code works in bash, but you're probably incorrectly running it with sh. In any case, use printf to avoid any unexpected expansions:
myString='\\\hello world'
printf '%s\n' "${myString}"

Try the following:
#!/bin/bash
test="\\\\\\hello world"
echo $test
You need to mask each special char (backslash) with an backslash. You need 3 special chars, so you need 3 backslashs.

Related

Convert multiline string in a variable in bash to a single-line string with newlines escaped

I am looking for a way to convert a multiline string in a variable in bash to a single-line string that has each \n character escaped as the \n literal.
For example:
str="
Hello
World
"
I need this to become Hello\nWorld. I looked through the questions on SO and Unix StackExchange but I haven't been able to find a command yet that achieves what I need.
Bash has two built-in ways to quote values suitable for re-ingestion. These will handle not only newlines but also tabs, quotes, and backslashes:
❯ echo "${str#Q}"
$'\nHello\nWorld\n'
❯ printf '%q\n' "$str"
$'\nHello\nWorld\n'
Alternatively, if you simply want to replace newlines and nothing else you can use ${var//search/replace} syntax to do replacements:
❯ echo "${str//$'\n'/\\n}"
\nHello\nWorld\n
Try:
sed -zn 's/\n/\\n/p' <<< "$str"
Use -z to consume the variable as one line and substitute new lines for literal newlines.

escape character usage in bash, what do we actually escape?

I am reading the bash manual, found the escape character definition pretty surprising, instead of modifying the meaning of every character follows it (as in Java / C):
It preserves the literal value of the next character that follows
Does it mean in bash, we only use it to escape special meaning character like ', ", \, $
And other cases, like \t\e\s\t actually is exactly as test ? I verified that
echo test
echo \t\e\s\t
outputs same result.
Does it mean in bash, we only use it to escape special meaning character like ', ", \, $
Yes. Also, e.g. newline:
echo foo
bar
# foo
# -bash: bar: command not found
echo foo \
bar
# foo
# bar
And other cases, like "\t\e\s\t" actually is exactly as "test"
If unquoted, yes. Quoted, the backslash is preserved. Some UNIX utilities do use backslash for "special meanings", but it is the utility, not bash, that gives those sequences meanings. Examples are printf, and GNU echo when given -e option:
/bin/echo \t\e\s\t
# test
/bin/echo "\t\e\s\t"
# \t\e\s\t
/bin/echo -e "\t\e\s\t" # GNU version (will not do the same thing on Mac)
# s
# (tab)(escape)s(tab)
printf "\t\e\s\t"
# s
# (tab)(escape)s(tab)
As #rici reminds me, bash can interpret C-style escape sequences itself, if you use the special quotes of the form $'...':
/bin/echo $'\t\e\s\t'
# s
Here it really is bash that does it, not echo.

I want to print $ in shell, but it is always deleted

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

ANSI escapes don't work in `printf`

When trying to use ANSI color escapes from a shell script, I was completely stuck, as the escape sequences (\e) were printed verbatim to the output.
#!/bin/sh
GREEN="\e[32m"
RED="\e[31m"
CLEAR="\e[0m"
printf "${GREEN}test passed${CLEAR}\n"
printf "${RED}test failed${CLEAR}\n"
Produces
\e[32mtest passed\e[0m
\e[31mtest failed\e[0m
\e is not recognized by POSIX sh (as mentioned by honzasp), but \033 is.
GREEN='\033[32m'
CLEAR='\033[0m'
printf "${GREEN}testpassed${CLEAR}\n"
Generally, it's safer to not expand parameters inside the first argument to printf (consider, for example FOO="hello %s"; printf "$FOO bar \n" baz;). However, this requires you to embed an actual escape character in your parameters, rather than a string that printf interprets as an escape character.
GREEN=$(printf '\033[32m')
CLEAR=$(printf '\033[0m')
printf '%stest passed%s' "$GREEN" "$CLEAR"
The solution is to use #!/bin/bash instead of #!/bin/sh in the first line, because raw sh's printf doesn't understand the escapes.

How can I do ANSI C quoting of an existing bash variable?

I have looked at this question, but it does not cover my use case.
Suppose I have the variable foo which holds the four-character literal \x60.
I want to perform ANSI C Quoting on the contents of this variable and store it into another variable bar.
I tried the following, but none of them achieved the desired effect.
bar=$'$foo'
echo $bar
bar=$"$foo"
echo $bar
Output:
$foo
\x61
Desired output (actual value of \x61):
a
How might I achieve this in the general case, including non-printable characters? Note that in this case a was used just as an example to make it easier to test whether the method worked.
By far the simplest solution, if you are using bash:
printf %b "$foo"
Or, to save it in another variable name bar:
printf -v bar %b "$foo"
From help printf:
In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:
%b expand backslash escape sequences in the corresponding argument
%q quote the argument in a way that can be reused as shell input
%(fmt)T output the date-time string resulting from using FMT as a format
string for strftime(3)
There are edge cases, though:
\c terminates output, backslashes in \', \", and \? are not removed,
and octal escapes beginning with \0 may contain up to four digits
The following works:
eval bar=\$\'$x\'
The command bar=$'\x61' has to be constructed first, then eval evaluates the newly built command.
I just found out that I can do this. Edited based on comments.
bar=$( echo -ne "$foo" )
The best method I know is
y=$(printf $(echo "$foo"|sed 's/%/%%/g'))
As mentioned in the comments, this trims trailing newlines from $foo. To overcome this:
moo=$(echo "${foo}:end"|sed 's/%/%%/g')
moo=$(printf "$moo")
moo=${moo%:end}
# the escaped string is in $moo
echo "+++${moo}---"
Since bash 4.4 there is a variable expansion to do exactly that:
$ foo='\x61'; echo "$foo" "${foo#E}"
\x61 a
To set another variable use:
$ printf -v bar "${foo#E}"; echo "$bar"
a
Sample of conversion via shell. Problem, the code is octal using \0nnn and hexdecimal (not on all shell) using \xnn (where n are [hexa]digit)
foo="\65"
print "$( echo "$foo" | sed 's/\\/&0/' )"
5
with awk, you could certainly convert it directly

Resources