為什麼 zip 和 rm 指令中的通配符 * 如此不同?

為什麼 zip 和 rm 指令中的通配符 * 如此不同?

我編寫了一個腳本來為我執行一些文件操作。我使用通配符運算子*將函數應用於某種類型的所有文件,但有一點我不明白。我可以將unzip所有文件放在這樣的資料夾中

unzip "*".zip

但是,要隨後刪除所有 zip 文件,我需要這樣做

rm *.zip

也就是說,它不需要引號。另一方面,如果我只給它 * ,解壓縮就不起作用(給我一個警告“文件不匹配”)。

為什麼會有所不同?對我來說,這似乎是完全相同的操作。或者我錯誤地使用了通配符?

外卡簡介在 Unix 中,不要真正深入探討這一點,而且我無法在rmzip文件中找到任何內容。

我正在 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,並產生不同的結果。

相關內容