遞歸遍歷目錄中的文件

遞歸遍歷目錄中的文件

可以透過以下方式輕鬆地遞歸迭代目錄中的檔案:

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 -print0with 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 中的檔案名稱或路徑中的位元組,因此這應該可以處理所有奇怪的檔案名稱問題。

相關內容