
是否有人有一個模板 shell 腳本,用於ls
對目錄名稱清單執行某些操作並循環遍歷每個目錄並執行某些操作?
我打算ls -1d */
取得目錄名稱清單。
答案1
正如 @shawn-j-goff 和其他人建議的那樣,編輯不要在 glob 可以的地方使用 ls 。
只需使用一個for..do..done
循環:
for f in *; do
echo "File -> $f"
done
您可以將 替換*
為*.txt
或任何其他返回清單(檔案、目錄或任何相關內容)的 glob、產生清單的命令,例如 ,$(cat filelist.txt)
或實際將其替換為清單。
在do
循環中,您只需引用帶有美元符號前綴的循環變數($f
如上例所示)。你可以echo
這樣做或做任何你想做的事情。
例如,將.xml
目前目錄中的所有檔案重新命名為.txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
或者更好的是,如果您使用 Bash,則可以使用 Bash 參數擴展而不是生成子 shell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
答案2
使用 的輸出ls
來取得檔案名稱是一個壞主意。它可能導致腳本故障甚至危險。這是因為檔案名稱可以包含除/
和之外的任何字符null
,並且ls
不使用這些字符中的任何一個作為分隔符,因此如果檔案名稱包含空格或換行符,則您可以將要得到意想不到的結果。
有兩種非常好的迭代文件的方法。在這裡,我只是簡單地echo
示範如何使用檔案名稱執行某些操作;不過,你可以使用任何東西。
第一種是使用 shell 的本機通配功能。
for dir in */; do
echo "$dir"
done
shell 擴展*/
為循環讀取的單獨參數for
;即使檔案名稱中有空格、換行符或任何其他奇怪的字符,for
也會將每個完整的名稱視為一個原子單元;它不會以任何方式解析列表。
bash
如果您想遞歸地進入子目錄,那麼除非您的 shell 具有一些擴展的通配功能(例如s ) ,否則這是行不通的globstar
。工作在各種系統上,那麼下一個選項是使用find
.
find . -type d -exec echo '{}' \;
在這裡,該find
命令將調用echo
並向其傳遞檔案名稱參數。它對找到的每個文件執行一次此操作。與前面的範例一樣,沒有解析文件名列表;相反,檔案名稱完全作為參數發送。
該參數的語法-exec
看起來有點有趣。find
接受之後的第一個參數-exec
並將其視為要運行的程序,並將每個後續參數視為傳遞給該程序的參數。有兩個特殊的論點-exec
要看看。第一個是{}
;此參數被替換為前面部分find
產生的檔案名稱。第二個是;
,它讓我們find
知道這是傳遞給程式的參數清單的結尾;find
需要這個,因為您可以繼續使用更多用於find
和不用於執行程式的參數。原因是\
shell 也進行了;
特殊處理 - 它代表命令的結束,因此我們需要對其進行轉義,以便 shell 將其作為參數提供,find
而不是自己使用它;讓 shell 不對其進行特殊對待的另一種方法是將其放在引號中:對於此目的';'
同樣有效。\;
答案3
對於包含空格的文件,您必須確保引用變量,例如:
for i in $(ls); do echo "$i"; done;
或者,您可以變更輸入欄位分隔符號 (IFS) 環境變數:
(IFS=$'\n';for i in $(ls); do echo $i; done) # subshell to restore IFS
最後,根據您在做什麼,您甚至可能不需要 ls:
for i in *; do echo "$i"; done;
答案4
只是為了添加 CoverosGene 的答案,這裡有一個只列出目錄名稱的方法:
for f in */; do
echo "Directory -> $f"
done