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

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

Related

running ffmpeg.exe from inside bash file [duplicate]

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.

How to escape characters from a single command?

How do I escape characters in linux using the sed command?
I want to print something like this
echo hey$ya
But I'm just receiving a
hey
how can escape the $ character?
The reason you are only seing "hey" echoed is that because of the $, the shell tries to expand a variable called ya. Since no such variable exists, it expands to an empty string (basically it disappears).
You can use single quotes, they prevent variable expansion :
echo 'hey$ya'
You can also escape the character :
echo hey\$ya
Strings can also be enclosed in double quotes (e.g. echo "hey$ya"), but these do not prevent expansion, all they do is keep the whole expression as a single string instead of allowing word splitting to separate words in separate arguments for the command being executed. Using double quotes would not work in your case.
\ is the escape character. So your example would be:
~ » echo hey\$ya
hey$ya
~ »

does quote removal happen after command substitution in a POSIX shell?

The POSIX shell standard at
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04
says in Section 2.6:
command substitution (...) shall be performed
(...)
Quote removal (...) shall always be performed last.
It appears to me that quote removal is not performed after command substitution:
$ echo "#"
#
$ echo '"'
"
as expected, but
$ echo $(echo '"')#"
>
What am I not understanding?
Added after reading answer/comments:
From what everybody is saying, the consideration of quotes happens at the very beginning of parsing, for example, to decide if a command is even "acceptable". Then why does the standard bother to emphasise, that the quote removal is performed late in the process??
"then the outer command becomes echo "#" and is balanced"
That is not 'balanced' because the first double-quote does not count. Quotes are only meaningful as quotes if they appear unencumbered on the command line.
To verify, let's look at this:
$ echo $(echo '"')#
"#
That is balanced because the shell does considers that " to be just another character.
By contrast, this is unbalanced because it has one and only one shell-active ":
$ echo $(echo '"')#"
>
Similar example 1
Here we show the same thing but using parameter expansion instead of command substitution:
$ q='"'; echo $q
"
Once the shell has substituted " for $q, one might think that there was an unbalanced double-quote. But, that double-quote was the results of parameter expansion and is therefore not a shell-active quote.
Similar example 2
Let's consider a directory containing file:
$ ls
file
$ ls "file"
file
As you can see above, quote removal is perfomed before ls is run.
But, consider this command:
$ echo ls $(echo '"file"')
ls "file"
As you can see ls $(echo '"file"') expands to ls "file" which is the command which ran successfully above. Now, let's try running that:
$ ls $(echo '"file"')
ls: cannot access '"file"': No such file or directory
As you can see, the shell does not treat the double-quotes that remain after command substitution. This is because those quotes are not considered to be shell-active. As a consequence, they are treated as normal characters and passed on to ls which complains that the file whose name begins and ends with " does not exist in the directory.
The same is happening here:
$ cmd='ls "file"'
$ $cmd
ls: cannot access '"file"': No such file or directory
POSIX standard
From the POSIX standard:
Enclosing characters in single-quotes ( ' ' ) shall preserve the
literal value of each character within the single-quotes
In other words, once the double-quote appears inside single quotes, it has no special powers: it is just another character.
The standard also mentions escaping and double-quotes as methods of preserving "the literal value" of a character.
Practical consequences
People new to shell often want to store a command in a variable as in the cmd='ls "file"' example above. But, because quotes and other shell-active characters cease to be shell active once they are stored in a variable, the complex cases always fail. This leads to a classic essay:
"I'm trying to put a command in a variable, but the complex cases always fail!"

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

Must special characters in bash double quoted or escaped with \

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.

Resources