简体   繁体   中英

Assumption with double quotes, single quotes & no quotes

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.

  1. 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]

  1. 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 $(())

  2. 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 '"' "'"

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".

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

  1. 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 
  2. 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] 
  3. 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 

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM