繁体   English   中英

双引号,单引号和无引号的假设

[英]Assumption with double quotes, single quotes & no quotes

在bash中:

使用双引号

echo "*" #Globbing is never done
echo "$variable" # Variable expansion is always done
echo "$(command)" # command expansion is always done

使用单引号

echo '*' #Globbing is never done 
echo '$variable' # Variable expansion is never done
echo '$(command)' # command expansion is never done

不使用引号

echo * #Globbing always done.
echo $variable; # Variable expansion is always done
echo $(command) # command expansion is always done

这适用于所有命令吗?

看起来你正在寻找异常,我猜你有一些想法。 我将假设set -f / set -o noglob被排除在这种情况之外?

当您使用dd命令时,即使没有引用,也不会出现globbing。

$ 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

反驳和误报

以下是一些奇怪的例子,但请遵循扩展

variable='2010-09-08 12:34:56' echo "$variable" | xargs date +%s -d date: extra operand '12:34:56'

额外的操作数显示变量扩展正在发生,您正在丢失管道中的引号。 $ date +%s -d 2010-09-08 12:34:56 date: extra operand '12:34:56'

如果您创建一个脚本echo $1 ,然后在传递时展开您的引用变量,也会发生这种情况。 它扩展,并按预期工作。 所以,问题不在于xargs,而在管道之前的扩展是正常的。

  1. Eval ...... evals的全部目的是在运行命令之前扩展其args。 扩展也发生在bash -c ,除了它需要一个参数。 因此,这不是一个扩展问题,而是一个命令使用问题。

cmd='printf "%s\\n" "$(date -d "$variable" +%c)"' bash -c $cmd

与扩展版本的工作方式相同

$ bash -c printf "%s\\n" "$(date -d "$variable" +%c)" printf: usage: printf [-v var] format [arguments]

  1. 我真的很喜欢Hauri的$'...'和$“......”信息 - 然而,这些与我们谈论的不一样。 实际上它们就像bash手册页所说的那样。 $''与''不同,因为(())来自$(())

  2. 我很兴奋这个,所以... $ ls mclark.txt qt sign_in.txt skel.bash $ zip m*t.zip *t $ ls *.zip m*t.zip

然而,这也不对 - splat扩展,但是在没有匹配时zip将其用作文字。 我找到了一些执行此操作的命令,但如果有匹配(我之后添加了my.zip),则使用匹配的扩展(抛出错误,b / c my.zip是用于测试目的的文本文件)。

有多种力量到位。 通常,您可以假设单引号是隐藏bash扩展中的内容。 双引号是对可能具有空格的值进行分组,以便bash将它们视为一个逻辑单元,但也禁用globbing。 虽然有很多警告......

用双引号括起字符会保留引号内所有字符的字面值,但$,',\\除外,并且,当启用历史记录扩展时,! 字符$和'在双引号内保留其特殊含义。 反斜杠只有在跟随以下字符之一时才保留其特殊含义:$,',“,\\或者。双引号可以在双引号内引用,前面加一个反斜杠。如果启用,将执行历史记录扩展除非出现在双引号中的!使用反斜杠进行转义。不会删除反斜杠!

请参阅man bash QUOTING部分

下面的这个例子将使您进一步混淆或使其更清晰。

$ echo "*test*"
*test*

$ echo '*test*'
*test*

$ msg=$(echo '*test*')
$ echo '$msg'
$msg

$ echo "$msg"
*test*

$ echo $msg
speedtest test1 test2 test3 test4 test5 testdir

请注意,如果没有匹配,它将打印*test*而不是空行,如Hastur所评论。

其他一些有趣的花絮

请注意,这不起作用

$ echo 'single quotes don\'t escape'

但这很有效

$ echo "\"double quotes\" escape"

但你可以使用其中一个而不逃避

$ echo '"' "'"

如果没有任何内容匹配* .xtx而a.txt是文件mv a.txt * .xtx也会得到意想不到的结果。 这同样适用于其他类似cp的东西,甚至将其视为引用:

$ ls *.xtx
/bin/ls: cannot access *.xtx: No such file or directory
$ echo "A" > *.xtx
$ ls *.xtx
*.xtx
$

虽然他们都应该返回错误,就像有一个文件更多,你会得到“模糊的重定向”。

简短回答:是的

总的来说 ,这种假设基本上是正确的!

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.

  1. xargs这样的命令正好适用于扩展和参数分配。

     echo "$variable" | xargs date +%s -d date: extra operand '12:34:56' Try 'date --help' for more information. 

    你必须使用-0 arg到xargs

     echo "$variable" | xargs -0 date +%s -d 1283942096 
  2. Builtin命令可以使用不同的args,特别是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. bash下有趣的东西的语法不仅限于".."'..'${}

    • $'...'允许您打印特殊字符,但不扩展变量:

       echo $'This\\tis\\ta string containing ${variable}' This is a string containing ${variable} 
    • 反引号 :出于兼容性考虑,反引号总是支持。 如果不是非常易读,您可能会在某些脚本中看到这一点:

       echo `date +%c -d "${!vname}"` Wed Sep 8 12:34:56 2010 
    • 语法$"..."可用于本地化:

       export TEXTDOMAIN=bash export LANG=fr_CH.utf-8 echo $"Running" En cours d'exécution 

这适用于所有命令吗?

是。

来自Bash参考手册:

3.1.2.2单引号

用单引号( ' )括起字符可以保留引号中每个字符的字面值。 单引号之间可能不会出现单引号,即使前面有反斜杠也是如此。

3.1.2.3双引号

用双引号括起来的字符( " )保留引号内所有字符的字面值,但$,`,\\除外,并且,当启用历史扩展时,!。字符$和`在double中保留它们的特殊含义引号(参见Shell Expansions )。反斜杠只有在跟随以下字符之一时才保留其特殊含义:$,`,“,\\或newline。 在双引号内,将删除后跟其中一个字符的反斜杠。 没有特殊含义的字符前面的反斜杠不做修改。 双引号可以在双引号内引用,前面加一个反斜杠。 如果启用,将执行历史记录扩展,除非! 出现在双引号中使用反斜杠进行转义。 之前的反斜杠! 没有删除。

在双引号中,特殊参数*和@具有特殊含义(参见Shell参数扩展 )。

shell参考手册和shell手册页可能包含预期的行为......但结果可能并不总是最初的预期。

阅读手册页的“QUOTING”部分也很有意思。 这是bash手册页中有关单引号和双引号的部分:(与参考手册的内容几乎相同)

用单引号括起字符可以保留引号中每个字符的字面值。 单引号之间可能不会出现单引号,即使前面有反斜杠也是如此。

用双引号括起字符会保留引号内所有字符的字面值,但$,`,\\除外,并且,当启用历史记录扩展时,! 字符$和`在双引号中保留其特殊含义。 反斜杠只有在跟随以下字符之一时才会保留其特殊含义:$,`,“,\\或者。双引号可以在双引号之前用反斜杠引用。如果启用,则历史记录将扩展除非使用反斜杠转义出现在双引号中的!,否则不会删除!之前的反斜杠。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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