Ubuntu

使用 find exec 計算嵌套在子目錄中的 csv 文件中的行數

  • March 5, 2021

我想find對一些嵌套的 csv 文件的結果執行兩個管道命令,但我失敗了。

這是想法:

$ find ./tmp/*/ -name '*.csv' -exec tail -n +2 {} | wc -l \;

為了計算每個 CSV 文件的標題行。

該命令失敗:

wc: ';': No such file or directory
find: missing argument to `-exec'

在那種情況下我真的需要做一個for循環嗎?

例如:

$ for f in ./tmp/*/*.csv; do tail -n +2 ${f} | wc -l; done

但是這樣一來,我就失去了很好的輸出,find其中確實包括計數中的文件名。

使用此解決方案時,我也失去了文件名:find -exec 中的管道命令?

$ find ./tmp/*/ -type f -name "*.csv" -print0 | while IFS= read -d '' f; do tail -n +2 "${f}" | wc -l; done

有點精確;當我談到列印的文件名時,這是因為我在單個文件上呼叫命令時習慣了以下結果:

$ tail -n +2 | wc -l ./tmp/myfile.csv 
2434 ./tmp/myfile.csv

我使用 Ubuntu 18.04。

如果你寫

find ... -exec foo | bar \;

find在呼叫之前,豎線由您的 shell 解釋。結果管道的左手是find ... -exec foo,這顯然給出了“缺少’-exec’的參數”錯誤;管道的右手是bar.

保護豎線不受外殼影響,如

find ... -exec foo \| bar \;

沒有幫助,因為之後的第一個標記-exec被解釋find為命令,並且所有後續標記,直到(但不包括);+終止符,都被視為該命令的參數。

有關詳細說明,請參閱了解 find 的 -exec 選項

要使用管道,-exec您需要呼叫 shell。例如:

find ./tmp/*/ -name '*.csv' -exec sh -c '
 printf "%s %s\n" "$(tail -n +2 "$1" | wc -l)" "$1"' mysh {} \;

然後,為了避免冒“參數列表太長”錯誤的風險,./tmp/*/可以重寫為

find ./tmp -path './tmp/*/*' ...

或者,更準確地說,也排除tmp的隱藏子目錄(./tmp/*/預設情況下可能會這樣做),如

find ./tmp -path './tmp/.*' -prune -o -path './tmp/*/*' ...

最後,您可以使用更快的-exec ... {} +變體,它避免為任何單個找到的文件呼叫 shell。例如,用andawk代替:tail``wc

find ./tmp -path './tmp/.*' -prune -o -path './tmp/*/*' \
 -name '*.csv' -exec awk '
   BEGIN { skip = 1 }
   FNR > skip { lc[FILENAME] = (FNR - skip) }
   END { for (f in lc) print lc[f],f }' {} +

(請注意,這awk也計算那些不以換行符結尾的格式錯誤的行,而wc沒有)。

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