為什麼文件存在時for循環中的zip
可以工作,但不存在時卻不行?
我有一個包含幾個子目錄的目錄。有一個關於壓縮文件的問題,其中包含我根據需要稍微修改過的答案。
for i in */; do zip "zips/${i%/}.zip" "$i*.csv"; done
但是,我遇到了一個奇怪的問題。對於第一組
zips/<name>.zip
不存在的文件夾,我收到此錯誤:zip error: Nothing to do! (zips/2014-10.zip) zip warning: name not matched: 2014-11/*.csv
但是,當我只是
echo
zip 語句時:for i in */; do echo zip "zips/${i%/}.zip" "$i*.csv"; done
然後執行回顯命令 (
zip zips/2014-10.zip 2014-10/*.csv
),它可以正常工作並壓縮文件夾。然後有趣的部分是原始命令的後續執行實際上將壓縮第一次不起作用的文件夾!要自己測試此行為:
cd /tmp mkdir -p 2016-01 2016-02 2016-03 zips for i in 2*/; do touch "$i"/one.csv; done for i in 2*/; do touch "$i"/two.csv; done zip zips/2016-03.zip 2016-03/*.csv for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done
你會看到 echo 列印出這些語句:
zip zips/2016-01.zip 2016-01/*.csv zip zips/2016-02.zip 2016-02/*.csv zip zips/2016-03.zip 2016-03/*.csv
但是,實際的 zip 命令會告訴您:
zip warning: name not matched: 2016-01/*.csv zip error: Nothing to do! (zips/2016-01.zip) zip warning: name not matched: 2016-02/*.csv zip error: Nothing to do! (zips/2016-02.zip) updating: 2016-03/one.csv (stored 0%) updating: 2016-03/two.csv (stored 0%)
所以它實際上是用 zip 文件
.csv
所在的 s 更新 zip 文件,而不是在創建 zip 文件時。如果您複製其中一個 zip 命令:$ zip zips/2016-02.zip 2016-02/*.csv adding: 2016-02/one.csv (stored 0%) adding: 2016-02/two.csv (stored 0%)
然後重新執行 zip-all-the-things:
for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done
您會看到它針對
2016-02
和更新2016-03
。這是我的輸出tree
:. ├── 2016-01 │ ├── one.csv │ └── two.csv ├── 2016-02 │ ├── one.csv │ └── two.csv ├── 2016-03 │ ├── one.csv │ └── two.csv └── zips ├── 2016-02.zip └── 2016-03.zip
此外,(不)令人驚訝的是,這很好用:
zsh -c "$(for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done)"
我在這裡做錯了什麼?(注意,我使用的是 zsh 而不是 bash,如果這有什麼不同的話)
通過外殼擴展
周圍的報價
"$i*.csv"
有所不同。使用引號,shell 將該字元串擴展為“2014-11/*.csv”。該確切文件不存在,並zip
報告錯誤。沒有引號,*
也擴展(通過文件名擴展/“globbing”),生成的zip
命令是匹配文件的完整列表,每個作為單獨的參數。for
您可以在循環內獲得第二種行為:for i in */ ; do zip "zips/${i%/}.zip" "$i"*.csv ; done
通過 zip 擴展
zip
也可以為自己擴展萬用字元,但不是在所有情況下。從zip 手冊:zip程序可以對正在修改的zip存檔中的名稱進行相同的匹配,或者在使用**-x**(排除)或**-i**(包含)選項的情況下,對要操作的文件列表進行相同的匹配,方法是使用反斜杠或引號告訴 shell 不要進行名稱擴展。
在您成功創建檔案後,原始命令適用於後續嘗試,因為
zip
嘗試將萬用字元與現有檔案的內容進行匹配。它們存在於那裡,並且仍然存在於文件系統中,因此它們被報告為updating:
.要在創建存檔
zip
時處理萬用字元,請使用(recurse) 選項遞歸到請求的目錄,並(include) 將其限制為與模式匹配的文件:-r``-i
for i in */ ; do zip -r "zips/${i%/}.zip" "$i" -i '*.csv' ; done