Bash
Bash:移動特定模式的文件
我編寫了一個腳本,它遍歷一組 zip 文件,提取它們並僅將與特定文件名模式匹配的文件移動到另一個文件夾。
劇本:
#!/bin/bash ARCHIVE_FILEMASK="????-??-??_E_MDT_0_0.7z" FILEMASK="?????????_?????_A_?_????????????????-?????????" extractDir=/path/to/dir dest=/path/to/dest for f in ${ARCHIVE_FILEMASK} do 7z e -aoa -o"${extractDir}" "$f" if [ $? != 0 ] then mv "${extractDir}/${FILEMASK}".xml "$dest" fi done
執行腳本時發生錯誤:
mv: cannot stat `/path/to/dir/?????????_?????_A_?_????????????????-?????????.xml': No such file or directory
我已經嘗試打開 nullglob 和 extglob,但沒有幫助。如果我直接從 shell 執行命令,它執行得很好。其他有類似問題的文章的答案也沒有幫助。
編輯: 在 Paweł Rumian 提到目錄名稱中的空格可能存在問題後,我嘗試了 AVJ 的提示並在命令
set +x
之前添加。mv
結果是:
+ mv '/path/to/dir/?????????_?????_A_?_??????????????????-????? ????.xml' /path/to/dest
所以很明顯我現在必須擺脫單引號。知道怎麼做嗎?
在變數擴展周圍加上雙引號的通常建議是,因為
$foo
外部引號的意思是“取 的值foo
,將其拆分為空格¹,如果每個結果單詞與至少一個文件匹配,則將其擴展為萬用字元模式”,而不是“取值的foo
”。特別是當變數foo
包含文件名時,"$foo"
是你需要的。但這裡的變數ARCHIVE_FILEMASK
並FILEMASK
包含萬用字元模式。因此,您實際上確實希望在使用它們時擴展它們,因此您應該不加引號地使用它們。因此,它們將被解釋為以空格分隔的模式列表;這在這裡沒有什麼區別,因為這些變數的值中沒有空格。變數
f
和extractDir
包含文件名,因此它們必須保持雙引號。for f in ${ARCHIVE_FILEMASK} do if 7z e -aoa -o"${extractDir}" "$f"; then mv "${extractDir}/"${FILEMASK}.xml "$dest" fi done
由於您使用的是 bash,因此如果萬用字元模式與任何文件都不匹配,則可以呼叫
shopt -s nullglob
以將其擴展為空列表。如果您不向其傳遞任何源文件,"${extractDir}/"${FILEMASK}.xml
該命令將抱怨它缺少文件;mv
您可以通過僅在至少有一個匹配項時呼叫它來解決該問題。shopt -s nullglob for f in ${ARCHIVE_FILEMASK} do if 7z e -aoa -o"${extractDir}" "$f"; then matches=("${extractDir}/"${FILEMASK}.xml) if ((${#matches[@]})); then mv "${matches[@]}" "$dest" fi fi done
¹或更一般地,如 所示
IFS
。