簡體   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