
可以透過以下方式輕鬆地遞歸迭代目錄中的檔案:
find . -type f -exec bar {} \;
然而,上面的方法不適用於更複雜的事情,因為需要完成許多條件分支、循環等。我曾經在上面使用過這個:
while read line; do [...]; done < <(find . -type f)
但是,這似乎不適用於包含模糊字元的檔案:
$ touch $'a\nb'
$ find . -type f
./a?b
有沒有其他方法可以很好地處理這些晦澀的字符?
答案1
還有一個用途安全的find
:
while IFS= read -r -d '' -u 9
do
[Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )
(這適用於任何 POSIX find
,但 shell 部分需要 bash。使用 *BSD 和 GNU find ,您可以使用-print0
代替-exec printf '%s\0' {} +
,它會稍微快一些。)
這使得在循環內使用標準輸入成為可能,並且它可以與任何小路。
答案2
這樣做很簡單:
find -exec sh -c 'inline script "$0"' {} \;
或者...
find -exec executable_script {} \;
答案3
最簡單(但安全)的方法是使用 shell 通配符:
$ for f in *; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
h:
要使上述遞歸到子目錄(在 bash 中),您可以使用該globstar
選項;也設定dotglob
為符合名稱以以下開頭的檔案.
:
$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
:foo:
:foo/file1:
:foo/file two:
h:
請注意,直到 bash 4.2,**/
遞歸到目錄的符號連結。從 bash 4.3 開始,**/
僅遞歸到目錄,例如find
.
另一個常見的解決方案是使用find -print0
with xargs -0
:
$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e f:
:./a b:
:./-e:
:./c
d:
請注意,h:/g
實際上是正確的,因為文件名包含\r
.
答案4
可移植地執行讀取循環有點困難,但特別是對於 bash,您可以嘗試類似的方法這。
相關部分:
while IFS= read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)
它指示find
列印由 NUL 字元 (0x00) 分隔的輸出,並read
取得 NUL 分隔的行 ( -d $'\0'
),而不將反斜線處理為其他字元的轉義 ( -r
),並且不對行進行任何分詞 ( IFS=
)。由於 0x00 是不能出現在 Unix 中的檔案名稱或路徑中的位元組,因此這應該可以處理所有奇怪的檔案名稱問題。