find/exec ステートメントの結果をカウントする

find/exec ステートメントの結果をカウントする

簡単な呼び出しで変更しなければならない Perl ファイルがいくつかありますsed。基本的には、すべての最初の行を削除する必要があります。現在、私はこれを実行できました:

find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \;

ただし、この行をスクリプトで使用しているため、もう少し... 詳しく表示したいと考えました。そこで、これまでに処理されたファイル数を示すカウンターを (リアルタイムで) エコーすることにしました。

Perlファイルの数は次のように取得できることは知っています

PERL_FILE_COUNT=$(find <PATH> -name "*.pl" | wc -l)

現在、私はこれを持っています

remove_first_line()
{
    count=0
    echo -ne "Removing first line of Perl files ..."
    find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \; >/dev/null 2>&1

    if [ $? -eq 0 ]
        then echo "OK"
        then echo "FAILED"
    fi
}

さて、出力として私が望むのは次のようなものです。

"Removing first line of Perl files ... 1/209209"

countそして、値は自動的に更新されるはずです。しかし、find/exec ステートメントで変数を増分する方法がわかりません。基本的に、sedファイルの作業が完了するたびに、count変数を増分する必要があります。

答え1

bash 4 を使用している場合は、代わりに globstar の使用を検討してください。これにより、再帰的なグロブが可能になります。

shopt -s globstar
perlz=( **/*.pl ) # */ Hack to fix syntax highlighting
totes="${#perlz[@]}"
i=0
for file in "${perlz[@]}"; do
    printf 'Removing first line of Perl files … %d/%d\r' $((++i)) $totes
    ed -s "$file" <<< $'1d\nw' # You can use `sed` if you want to, but ed is an actual file editor
done
echo # print a final newline

このソリューションは、名前に奇妙な文字が含まれるファイル間で機能し、サブシェルを回避します。

ただし、bash 4 が選択肢にない場合は、次を使用してこのソリューションを再作成できますfind -exec +

find . -name '*.pl' -exec bash -c 'totes=$#
  i=0
  for file; do
    printf "Removing first line of Perl files … %d/%d\r" $((++i)) $totes
    ed -s "$file" <<< $'\''1d\nw'\'' # Avoid these leaning toothpicks by putting this
                                     # script in a file.
  done
  echo # print a final newline
' bash {} +

ただし、これはシステムの ARG_MAX の影響を受けるため (上記とは異なり)、ファイル数が非常に多い場合は、ファイルのサブセットに対して複数回実行される可能性があります。

答え2

これはどう?

#!/bin/bash

failed=0

find . -type f -name "*.pl" | while read file; do
   if [ -e "$file" ] && [ -r "$file" ]; then
     sed -i~ "1d" "$file"
     if [ $? != 0 ]; then
        echo "sed returns $? on ($file)"
        (( failed++  ))
     fi
   else
      echo "warning ($file) not exists, or not readable"
      (( failed++ ))
   fi
done

echo "failed execution: $failed"

ここで使用する方が安全ですsed -i~。Sed は古いファイルを として保存しますfile~

答え3

GNU: について:

find . -type f -name '*.pl' -size +0c -print0 > list &&
  count=$(grep -cz . < list) &&
  stdbuf -oL xargs < list -r0 sed -i -e '1{w /dev/stdout' -e 'd;}' |
    awk -v c="$count" '{printf "processed file %d/%d\r", NR, c}
                       END{print ""}'

関連情報