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.
Related
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 am trying to printf an input with variables and need double quotes. My output needs a \x and \f text output.
printf "\x"
or
printf "\\x"
produces the error:
./pegrep.in: line 94: printf: missing hex digit for \x
while
printf "\f"
or
printf "\\f"
produces nothing at all (in a text output I believe it creates ^L)
single quotes however works for x (but not f). I tried enclosing
printf "...'\\x'..."
and got the same error as standard double quotes. Have also tried /// to no avail.
First, let's understand how quoting works.
The simplest form of quoting is the backslash: it prevents the following character from being interpreted in any special way, allowing it to be used as a literal character. For example:
# Two arguments to printf
$ printf '%s\n' a b
a
b
# One three-character argument to printf
printf '%s\n' a\ b
a b
Double quotes are equivalent to escaping every character contained therein: "a b c" is equivalent to \a\ \b\ \c, which is the same as a\ b\ c because a, b, and c have no special meaning to begin with. You can think of every character inside double quotes as being treated literally, with the following exceptions:
$ can start a parameter expansion or a command substitution. Escape it with a backslash to treat it literally.
$ foo=3
$ echo "$foo"
3
$ echo "\$foo"
$foo
A backquote starts a command substitution. Escape it with a backslash to treat it literally.
$ echo "`pwd`"
/home/me
$ echo "\`pwd\`"
`pwd`
A double quote ends a quoted string. Escape it with a backslash to treat it literally.
$ echo "\""
"
Because a backslash might be part of one of the three preceding sequences, escape it with a backslash to treat one literally.
$ echo "\\"
\
Inside single quotes, everything is treated literally, including any use of a backslash. (One consequence of this is that it is impossible to put a single quote in a single-quoted string, because it will always terminate such a string.)
$ echo '\'
\
Once you understand quoting, you next need to realize that printf itself can process whatever backslashes it sees in its first argument.
$ printf 'a\x20b\n' # a, space (ASCII 0x20), b, newline
a b
In order to ensure a string is printed literally no matter what characters are present, use the %s format specifier and pass your string as a second argument:
$ printf '\x41\n'
A
$ printf '%s\n' '\x41'
\x41
I think you may be confusing the \ and the % characters. The % is used to output formatted variable contents. I think this when \f is outputs ^L (aka ASCII FF) that escape sequence is working as documented.
The printf argument can be quoted with single quotes. Then you can use double quotes within it and they will be part of the output:
printf '"%x"' 4011 # output: "fab"
Similarly for floating point:
print '"%f"' 2.2 # output: "2.200000"
The \ character is for escape sequences of otherwise unprintable characters.
See man printf for a full list of the % format characters and their meanings.
In bash :
Using double quotes
echo "*" #Globbing is never done
echo "$variable" # Variable expansion is always done
echo "$(command)" # command expansion is always done
Using single quotes
echo '*' #Globbing is never done
echo '$variable' # Variable expansion is never done
echo '$(command)' # command expansion is never done
Using no quotes
echo * #Globbing always done.
echo $variable; # Variable expansion is always done
echo $(command) # command expansion is always done
will this apply for all commands?
It looks like you are looking for exceptions, and I'd guess you have some in mind. I'm going to make the assumption that set -f/set -o noglob are being excluded from this case?
When you use the dd command, globbing will not occure, even if unquoted.
$ ls *.txt
blah.txt file1.txt file2.txt file.txt logfile.txt
$ dd if=*.txt of=glob.txt
dd: failed to open ‘*.txt’: No such file or directory
Rebuttal and false positives
Here are some examples that are odd, but follow expansion
variable='2010-09-08 12:34:56'
echo "$variable" | xargs date +%s -d
date: extra operand '12:34:56'
The extra operand shows that variable expansion is happening, you are losing the quotes in the pipe.
$ date +%s -d 2010-09-08 12:34:56
date: extra operand ‘12:34:56’
This also happens if you create a script to echo $1 and then expand your quoted variable while passing. It expands, and works as expected. So, the issue is not with xargs, but with your expansion before the pipe which is normal.
Eval... evals whole purpose is to do expansion of its args prior to running a command. Expansion also happens with bash -c, except it takes one argument. So, again, this is not an expansion issue, but a command usage issue.
cmd='printf "%s\n" "$(date -d "$variable" +%c)"'
bash -c $cmd
works the same as the expanded version
$ bash -c printf "%s\n" "$(date -d "$variable" +%c)"
printf: usage: printf [-v var] format [arguments]
I really enjoyed Hauri's $'...' and $"..." information--however, those are not the samething we are talking about. They are in fact behaving as the bash man page says they should. $'' is as different from '' as (()) is from $(())
I got excited about this one, so...
$ ls
mclark.txt qt sign_in.txt skel.bash
$ zip m*t.zip *t
$ ls *.zip
m*t.zip
However, this isn't right either-- the splat expands, but upon no match zip uses it as a literal. I found a few commands that did this, but if there was a match (I added a my.zip later) it uses the matched expansion (an error was thrown, b/c my.zip was a text file for testing purposes).
There are multiple forces in place. In general you can assume that single quotes is to hide the contents from bash expansion. Double quotes is to group values which might have white space so that bash sees them as one logical unit but also disable globbing. There are many caveats though...
Enclosing characters in double quotes preserves the literal value of
all characters within the quotes, with the exception of $, ', \, and,
when history expansion is enabled, !. The characters $ and ' retain
their special meaning within double quotes. The backslash retains
its special meaning only when followed by one of the following
characters: $, ', ", \, or . A double quote may be quoted
within double quotes by preceding it with a backslash. If enabled,
history expansion will be performed unless an ! appearing in double
quotes is escaped using a backslash. The backslash pre-ceding the !
is not removed.
See section QUOTING from man bash
This example below, will either confuse you further or make it clearer.
$ echo "*test*"
*test*
$ echo '*test*'
*test*
$ msg=$(echo '*test*')
$ echo '$msg'
$msg
$ echo "$msg"
*test*
$ echo $msg
speedtest test1 test2 test3 test4 test5 testdir
note that if there were no matches it would print *test* not empty line as commented by Hastur.
some other interesting tidbits
note that this doesn't work
$ echo 'single quotes don\'t escape'
but this works
$ echo "\"double quotes\" escape"
but you can use one in other without escaping
$ echo '"' "'"
Short answer: Yes
This asumptions are basicaly true, alway!
variable='2010-09-08 12:34:56'
vname=variable
date -d "$variable" +%s
1283942096
date -d "${!vname}" +%s
1283942096
date -d $variable +%s
date: extra operand '+%s'
Try 'date --help' for more information.
date -d '$variable' +%s
date: invalid date '$variable'
date -d ${!vname} +%s
date: extra operand '+%s'
Try 'date --help' for more information.
But
Some commands like xargs work precisely about expansion and parameter distribution.
echo "$variable" | xargs date +%s -d
date: extra operand '12:34:56'
Try 'date --help' for more information.
You have to use -0 arg to xargs:
echo "$variable" | xargs -0 date +%s -d
1283942096
Builtin commands could use args differently, especialy eval:
cmd='printf "%s\n" $(date -d "$variable" +%c)'
eval $cmd
Wed
Sep
8
12:34:56
2010
cmd='printf "%s\n" "$(date -d "$variable" +%c)"'
eval "$cmd"
Wed Sep 8 12:34:56 2010
eval $cmd
Wed Sep 8 12:34:56 2010
bash -c "$cmd"
Mon May 16 00:00:00 2016
bash -c $cmd
printf: usage: printf [-v var] format [arguments]
Syntax of funny thing under bash are not limited to "..", '..', and ${}
$'...' let you print special characters, but don't expand variables:
echo $'This\tis\ta string containing ${variable}'
This is a string containing ${variable}
Backticks: For compatibility, backtick are always supported. If not very readable, you may see this in some scripts:
echo `date +%c -d "${!vname}"`
Wed Sep 8 12:34:56 2010
Syntaxe $"..." could be used for localization:
export TEXTDOMAIN=bash
export LANG=fr_CH.utf-8
echo $"Running"
En cours d'exécution
If nothing matches *.xtx while a.txt is a file
mv a.txt *.xtx
will get you an unexpected result too.
The same applies for other things like cp and even this treats it as quoted:
$ ls *.xtx
/bin/ls: cannot access *.xtx: No such file or directory
$ echo "A" > *.xtx
$ ls *.xtx
*.xtx
$
While they should all return error just like if there were more the one file you would get "ambiguous redirect".
will this apply for all commands?
Yes.
From Bash reference manuals:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (') preserves the literal
value of each character within the quotes. A single quote may not
occur between single quotes, even when preceded by a backslash.
and
3.1.2.3 Double Quotes
Enclosing characters in double quotes (") preserves the literal
value of all characters within the quotes, with the exception of $,
`, \, and, when history expansion is enabled, !. The characters
$ and ` retain their special meaning within double quotes (see
Shell Expansions). The backslash retains its special meaning only
when followed by one of the following characters: $, `, ", \,
or newline. Within double quotes, backslashes that are followed by one
of these characters are removed. Backslashes preceding characters
without a special meaning are left unmodified. A double quote may be
quoted within double quotes by preceding it with a backslash. If
enabled, history expansion will be performed unless an ! appearing
in double quotes is escaped using a backslash. The backslash preceding
the ! is not removed.
The special parameters * and # have special meaning when in double
quotes (see Shell Parameter Expansion).
Probably the shell reference manuals and the shell man pages contain the intended behavior ... but the result might not always be what was originally intended.
Reading the "QUOTING" section of the man pages is also intresting. This is a section from the bash man page concerning the single and double quotes: (which is pretty much the same content as the reference manual)
Enclosing characters in single quotes preserves the literal value of
each character within the quotes. A single quote may not occur
between single quotes, even when preceded by a backslash.
Enclosing characters in double quotes preserves the literal value of
all characters within the quotes, with the exception of $, `, \, and,
when history expansion is enabled, !. The characters $ and `
retain their special meaning within double quotes. The backslash
retains its special meaning only when followed by one of the following
characters: $, `, ", \, or . A double quote may be
quoted within double quotes by preceding it with a backslash. If
enabled, history expan- sion will be performed unless an !
appearing in double quotes is escaped using a backslash. The
backslash preceding the ! is not removed.
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.