grepを使用するときにファイルをスキップする

grepを使用するときにファイルをスキップする

特定の値でファイルを選択するように、次のbashコードをどのように変更しますか?たとえば、selcnt=3ファイル3つごとにパターンが検索され、selcnt=5ファイル5つごとにパターンが検索される式です。

grep -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
  while read f; do
    echo -e $(tput setaf 46)"==> $f <==\n"$(tput sgr0)
    grep -ni "${ictx[@]}" -e "$ptrn" -- "$f"
    echo ""
  done

目的は、検索プロセスを高速化しながら、出力を一度に1つのファイルに分割することです。プロセスを高速化する1つの方法は、たとえば、ファイルをスキップする方法で、実行ごとに異なるファイルを処理することです。

Run 1: Start from file 1 and skipping two files; 
Run 2: Start from file 2 and skipping two files;  
Run 3: Start from file 2 and skipping two files.   

最初の試みで、

ist=1; isk=2
grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}"  |
  sed -z '${ist}~${isk}!d'  |
  while IFS= read -rd '' fl; do
    printf '%s\n\n' "${grn}==> $fl <==${sgr}"
    grep -ni "${ictx[@]}" -e "$ptrn" -- "$fl"
  done

しかし、エラーが発生しました。

sed: -e expression #1, char 0: unmatched `{'

答え1

出力から3番目のファイルをすべて選択するには、まず任意のファイルパス(追加/オプション)grep -lを処理できるようにNULで区切られたリストに切り替える必要があることに注意してから、次のものを選択できます。--null-Zgrep

gawk -v RS='\0' -v ORS='\0' 'NR ~ 3 == 1'
sed -z '1~3!d' # assuming GNU sed
perl -0ne 'print if $. % 3 == 0'

次に、その出力を繰り返すには、次のようにします(zshまたはbashを使用)。

green=$(tput setaf 46) sgr0=$(tput sgr0)

while IFS= read -rd '' file; do
  printf '%s\n\n' "$green==> $file <==$sgr0"
  ...
done

echo -eファイル名に表示されるバックスラッシュ文字が壊れる可能性があるため、使用しないでください。

したがって、それらを1つにまとめます。

green=$(tput setaf 46) sgr0=$(tput sgr0)

grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
  sed -z '1~3!d' |
  while IFS= read -rd '' file; do
    printf '%s\n\n' "$green==> $file <==$sgr0"
    grep -ni "${ictx[@]}" -e "$ptrn" -- "$file"
  done

しかし、ポイントがこれらのループの3つを並列に実行し、各ループが3つのバッチのうちの1つを処理することである場合、これはGNUのような用途ですparallel

grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
  PARALLEL_SHELL=bash \
    GREEN=$(tput setaf 46) \
    SGR0=$(tput sgr0) \
    PTRN=$ptrn \
    parallel -m0kj3 '
    for file in {}; do
      printf "%s\n\n" "$GREEN==> $file <==$SGR0"
      grep -ni '"${ictx[@]@Q}"' -e "$PTRN" -- "$file"
    done'

ここで、スカラー変数は環境変数を介して渡されます。それ以外の場合は、${param@Q}bash-4.4+を使用して配列定義が内部bashインスタンスに渡されます(ここでは値にparallel{}...などの特殊文字列が含まれていないとします{.})。

あるいは、上記の制限を避ける方が良いです。

grep --null -r -l "${isufx[@]}" -e "$ptrn" -- "${fdir[@]}" |
  PARALLEL_SHELL=bash TRANSFER_CODE=$(
    green=$(tput setaf 46) sgr0=$(tput sgr0)
    typeset -p green sgr0 ptrn ictx
    ) parallel -m0kj3 '
    eval "$TRANSFER_CODE"
    for file in {}; do
      printf "%s\n\n" "$green==> $file <==$sgr0"
      grep -ni "${ictx[@]" -e "$ptrn" -- "$file"
    done'

今回使用された出力は、typeset -pこれらすべての変数(配列または非配列)の定義を内部的に送信しますbash

parallel3つのbashシェルが並列に開始され、各シェルはファイルの3分の1を処理し、最後に出力を順次再アセンブルします。

とにかくボトルネックがI / O(ディスクからデータを読み取る速度)の場合、これらのタスクを並列に実行することは役に立ちません。

関連情報