我編寫了一個腳本來為我執行一些文件操作。我使用通配符運算子*
將函數應用於某種類型的所有文件,但有一點我不明白。我可以將unzip
所有文件放在這樣的資料夾中
unzip "*".zip
但是,要隨後刪除所有 zip 文件,我需要這樣做
rm *.zip
也就是說,它不需要引號。另一方面,如果我只給它 * ,解壓縮就不起作用(給我一個警告“文件不匹配”)。
為什麼會有所不同?對我來說,這似乎是完全相同的操作。或者我錯誤地使用了通配符?
外卡簡介在 Unix 中,不要真正深入探討這一點,而且我無法在rm
或zip
文件中找到任何內容。
我正在 Mac (Yosemite) 上使用終端機。
答案1
你已經很好地解釋了情況。難題的最後一部分是它unzip
本身可以處理通配符:
http://www.info-zip.org/mans/unzip.html
論據
文件[.zip]
…
通配符表達式類似於常用的 Unix shell(sh、ksh、csh)中支援的通配符表達式,並且可能包含:
* 匹配0個或多個字元的序列
透過引用 * 通配符,您可以阻止 shell 擴展它,以便 shellunzip
看到通配符並根據自己的邏輯處理擴展它。
rm
相比之下,不支援通配符在其自己的,因此嘗試引用通配符將指示rm
在檔案名稱中尋找文字星號。
unzip *.zip
不起作用的原因是unzip
的語法根本不允許多個 zip 檔案;如果有多個參數,則期望第二個及後續參數是存檔中的檔案:
解壓縮 [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] 檔案[.zip] [檔案...] [-x x檔...] [-d exdir]
答案2
這兩個命令之間的差異在於引號*
字元。如果您在 shell 中呼叫命令並使用該*
字元作為參數,則 shell 本身將計算該參數。看這個例子:
$ ls
file1.zip file2.zip file3.zip file4.txt
現在有*
:
$ ls *.zip
file1.zip file2.zip file3.zip
shell 評估通配符並建立命令,如下所示:
$ ls file1.zip file2.zip file3.zip
使用帶有引號的通配符,它被解釋為名為(字面意思)的檔案*.zip
:
$ ls "*".zip
ls: cannot access *.zip: No such file or directory
unzip
無法使用多個壓縮檔案作為參數來呼叫該實用程式。但是,開發者為此選擇了另一種方式。從線上說明頁:
文件[.zip]
[...] 通配符表達式與常用 Unix shell(sh、ksh、csh)中支援的通配符表達式類似 [...] (請務必引用作業系統可能解釋或修改的任何字符,特別是在 Unix 和 VMS 下。
答案3
差別在於第一種情況是 shell 本身擴展了 glob:
% cd /
% echo *
Applications Library Network System Users Volumes bin cores ...
%
而在第二種情況下,應用程式本身會使用該文字字元執行 Something™:
% cd /
% perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.apple.launchd.aj4FEhYqm5
...
如果不加引號,shell 首先會擴展 glob,並且該命令將使用 shell glob 擴展成的任何內容來運行。
答案4
由於 zip 處理多個參數的方式,需要引號:
rm
:刪除參數清單中的所有文件
zip
:解壓縮第一個參數中的檔案。僅提取剩餘參數中的檔案。
$ ls *.zip
file1.zip file2.zip file3.zip
$ unzip *.zip
Archive: file1.zip
caution: filename not matched: file2.zip
caution: filename not matched: file3.zip
如您所見,它嘗試在 file1.zip 中尋找 file2.zip 和 file3.zip
為了允許您一次提取多個 zip 文件,zip 支援自行解釋 glob,並產生不同的結果。