Shell-Script

為什麼文件存在時for循環中的zip可以工作,但不存在時卻不行?

  • August 17, 2016

我有一個包含幾個子目錄的目錄。有一個關於壓縮文件的問題,其中包含我根據需要稍微修改過的答案。

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

但是,當我只是echozip 語句時:

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

引用自:https://unix.stackexchange.com/questions/303949