find execを使用して、サブディレクトリにネストされたcsvファイルの行数を計算します。

find execを使用して、サブディレクトリにネストされたcsvファイルの行数を計算します。

find一部のネストされたcsvファイルの結果に対して2つのパイプコマンドを実行したいが、悲惨に失敗します。

アイデアは次のとおりです。

$ 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を使用してください。

ベストアンサー1

書くなら

find ... -exec foo | bar \;

パイプは呼び出し前にシェルによって解釈されますfind。その結果、パイプの左側がありfind ... -exec foo、パイプの右側が「 '-exec'の引数の欠落」エラーが発生しているようですbar

ハウジングの損傷から垂直柱を保護します。

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

最初の次のトークンはコマンド-execとして解釈され、終了者まで(含まれていない)までのすべての後続のトークンはそのコマンドの引数と見なされるため役に立ちません。find;+

バラより「find」の-execオプションについて徹底した説明のために。

パイプを使用するには-execシェルを呼び出す必要があります。たとえば、

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 ... {} +最後に見つかった単一のファイルに対してシェルを呼び出さないより速いバリエーションを使用できます。たとえば、代わりにawk次を使用します。tailwc

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。)

おすすめ記事