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

목적은 검색 프로세스 속도를 높이면서 출력을 한 번에 하나의 파일로 분할하는 것입니다. 프로세스 속도를 높이는 한 가지 방법은 예를 들어 파일을 건너뛰는 방식으로 실행마다 다른 파일을 처리하는 것입니다.

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

출력에서 세 번째 파일을 모두 선택하려면 먼저 임의의 파일 경로(추가 / 옵션 ) 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파일 이름에 나타나는 백슬래시 문자가 깨질 수 있으므로 사용하지 마십시오 .

따라서 그것들을 하나로 합치십시오:

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셸이 병렬로 시작되며, 각 셸은 파일의 1/3을 처리하고 마지막에 출력을 순차적으로 다시 어셈블합니다.

어쨌든 병목 현상이 I/O(디스크에서 데이터를 읽는 속도)인 경우 이러한 작업을 병렬로 실행하는 것은 도움이 되지 않습니다.

관련 정보