簡體   English   中英

bash中`和'有什么區別?

[英]What's the difference between ` and ' in bash?

在OS X終端中運行此語句

for i in `ls -v *.mkv`; do echo $i; done

將按名稱順序成功打印出目錄中的所有文件名,每個文件名都在其自己的行上。

來源: 這個StackOverFlow答案

但是,如果我在OS X終端中運行此語句

for i in 'ls -v *.mkv'; do echo $i; done

輸出是“ls -v fileName1.mkv fileName2.mkv”等,所有文件名連接成一個長行(而不是每個都在自己的行上打印)。

我的問題是:

  1. bash中`和'有什么區別?
  2. 為什么這種差異對完全不同的輸出負責?
  3. 什么鍵盤組合產生`? (鍵盤組合)

1)執行反引號之間的文本並替換為所附命令的輸出,因此:

echo `echo 42`

將擴展為:

echo 42

這稱為命令替換 ,也可以使用語法$(command)來實現。 在您的情況下,以下內容:

for i in `ls -v *.mkv`; do ...

被替換為類似的東西(如果您的目錄包含3個名為a.mkvb.mkvc.mkv的文件 ):

for i in a.mkv  b.mkv  c.mkv; do ...

引號雙引號之間的文本只是普通的Bash字符串,其中包含空格中的字符(在Bash中引用字符串的其他方法在此處描述 ):

echo "This is just a plain and simple String" 
echo 'and this is another string' 

使用之間的差值'"是之間包圍的字符串"可以內插變量,例如:

variable=42
echo "Your value is $variable"

要么:

variable=42
echo "Your value is ${variable}"

打印:

Your value is 42

2) *.mkv類的通配符表達式在稱為Globbing的過程中被擴展的文件名替換 在大多數命令中使用通配符激活Globbing, 而不將表達式括在字符串中:

echo *.mkv

將打印:

a.mkv b.mkv c.mkv

與此同時:

echo "*.mkv"

打印:

*.mkv

你的for循環中的i變量取值為“ ls -v *.mkv ”,但是循環體內的echo命令需要$i不帶引號,所以Bash在那里應用了globbing,你最終會得到以下結果:

for i in 'ls -v *.mkv'; do 
   #   echo $i 
   #
   # which is expanded to:
   #   echo ls -v *.mkv    (no quotes) 
   #
   # and the globbing process transform the above into:
   echo ls -v a.mkv b.mkv c.mkv

在應用globbing之后,這只是一個帶有文件名的單行字符串。


3)這取決於您的鍵盤布局。

保持角色的一個技巧是使用程序ascii ,搜索角色96(十六進制60),復制它並將其保存在剪貼板上(您可以使用parcellite或任何其他適合您需要的剪貼板管理器)。


更新:正如@triplee建議的那樣 ,你應該檢查無用的ls因為這被認為是一個重擊陷阱,並且有更好的方法來實現你想要做的事情。

'expression',將在表達式中輸出確切的字符串。

`expression`,將執行表達式的內容並且echo輸出它。

例如:

 x="ls"
 echo "$x" --> $x
 echo `$x` --> file1 file2 ... (the content of your current dir)

反引號意味着“在反引號之間運行作為命令,然后表現得好像我在這里輸入了該命令的輸出”。 正如其他人所說,單引號意味着只是一個字符串。 所以在第一種情況下,會發生什么:

bash運行ls -v *.mkv作為命令,輸出如下內容:

fileName1.mkv
fileName2.mkv

然后bash將其替換回反引號包圍的命令所在的位置,即它有效地使你for聲明成為:

for i in fileName1.mkv fileName2.mkv; do echo $i; done

這有兩個“令牌”:“fileName1.mkv”和“fileName2.mkv”,所以循環運行它的主體( echo $i )兩次,每次一次:

echo fileName1.mkv
echo fileName2.mkv

默認情況下, echo命令在完成回顯你告訴它回顯的內容后會輸出一個換行符,這樣你就可以獲得你想要的輸出,每個文件名都在它自己的行上。

但是,當您使用單引號而不是反引號時,單引號之間的內容不會被評估; 即bash不會將其視為一個命令(或任何特殊的命令;單引號告訴bash,“這個文字並不特別;不要試圖評估它或對它做任何事情”)。 這意味着你正在運行的是這樣的:

for i in 'ls -v *.mkv'; do echo $i; done

其中只有一個標記,即文字字符串“ls -v * .mkv”,因此循環體僅運行一次:

echo ls -v *.mkv

...但是在bash運行該echo之前,它會擴展“* .mkv”。

我掩飾了這上面,但是當你做這樣的事情ls *.mkv ,它實際上不是ls做的轉換*.mkv到所有的.mkv文件名列表; 這就是bash。 ls永遠不會看到*.mkv ; ls運行時,bash已將其替換為“fileName1.mkv fileName2.mkv ...”。

同樣對於echo :在運行此行之前,bash會擴展*.mkv ,因此實際運行的是:

echo ls -v fileName1.mkv fileName2.mkv

輸出此文本:

ls -v fileName1.mkv fileName2.mkv

(*腳注:還有另一件我掩飾過的東西,那是文件名中的空格。反引號之間的ls輸出是一個文件名列表,每行一個。麻煩的是,bash看到任何空格 - 兩個空格和換行符 - 作為分隔符,所以如果你的文件名是:

file 1.mkv
file 2.mkv

你的循環將運行四次(“文件”,“1.mkv”,“文件”,“2.mkv”)。 有人提到的另一種形式的循環, for i in *.mkv; do ... for i in *.mkv; do ...沒有這個問題。 為什么? 因為當bash擴展“* .mkv”時,它在幕后做了一件聰明的事情並將每個文件名視為一個單元,就像你在引號中說“file 1.mkv”“file 2.mkv”一樣。 在你使用ls的情況下,它不能這樣做,因為在將擴展的文件名列表傳遞給ls ,bash無法知道返回的是那些相同文件名的列表。 ls本來可以是任何命令。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM