여러 모드를 사용하여 파일을 찾는 방법

여러 모드를 사용하여 파일을 찾는 방법

여러 패턴을 사용하는 파일을 찾고 싶습니다.

이것은 내 원래 명령입니다. 그러나 입력이 매우 길고 xargs zgrep중복됩니다. 입력할 패턴이 10개 이상이라면 어떻게 될까요?

find -mtime -$a -type f ! -name "*.bak*" | xargs zgrep -il "$b" | xargs zgrep -il "$c" | xargs zgrep -il "$d" | xargs zgrep -il 'ST.997' | sort -u

예를 들어 다음과 같이 더 적은 문자를 입력하고 싶습니다.

find -mtime -$a -type f ! -name "*.bak*" | xargs zgrep -il "$b && $c && $d" | sort -u

편집하다:이러한 패턴이 $. 이는 명령이 스크립트 내부에 있고 이러한 변수에 문자열/숫자 값이 있기 때문입니다.

나는 이를 사용하여 스크립트, 특히 런타임을 개선할 것입니다.

답변1

각 모드마다 파일 압축을 계속해서 풀지 않으려면 다음을 수행할 수 있습니다.

PATTERNS='foo
bar
baz' find . -mtime -"$a" -type f ! -name "*.bak*" -exec awk -v q=\' '
  function shquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  BEGIN {
    n = split(ENVIRON["PATTERNS"], pats, "\n")
    for (arg = 1; arg < ARGC; arg++) {
      file = ARGV[arg]
      cmd = "gzip -dcf < " shquote(file)
      for (i = 1; i <= n; i++) notfound[pats[i]]
      left = n
      while (left && (cmd | getline line) > 0) {
        for (pat in notfound) {
          if (line ~ pat) {
            if (!--left) {
              print file
              break
            }
            delete notfound[pat]
          }
        }
      }
      close(cmd)
    }
    exit
  }' {} +

스키마는 다음과 같이 처리됩니다.awkgrep -E/supported 확장 정규 표현식 과 유사한 패턴입니다 egrep. 대소문자를 구분하지 않는 일치를 위해 -v IGNORECASE=1GNU를 사용하여 if를 추가 awk하거나 다음과 같이 이식 가능하게 변경할 수 있습니다.

PATTERNS='foo
bar
baz' find . -mtime -"$a" -type f ! -name "*.bak*" -exec awk -v q=\' '
  function shquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  BEGIN {
    n = split(tolower(ENVIRON["PATTERNS"]), pats, "\n")
    for (arg = 1; arg < ARGC; arg++) {
      file = ARGV[arg]
      cmd = "gzip -dcf < " shquote(file)
      for (i = 1; i <= n; i++) notfound[pats[i]]
      left = n
      while (left && (cmd | getline line) > 0) {
        line = tolower(line)
        for (pat in notfound) {
          if (line ~ pat) {
            if (!--left) {
              print file
              break
            }
            delete notfound[pat]
          }
        }
      }
      close(cmd)
    }
    exit
  }' {} +

(스키마에 비표준 ERE 확장이 없다고 가정하면(예: ) \S로 변환됩니다 \s.

awk명령을 zgrep-many스크립트에 넣어 사용하기 쉽게 만들 수 있습니다. 그것은 다음과 같습니다:

#! /bin/sh -

usage() {
  cat >&2 << EOF
Usage: $0 [-e <pattern>] [-f <file] [-i] [pattern] files

List the files for which all the given patterns are matched.
EOF
  exit 1
}

ignorecase= 
PATTERNS=
export PATTERNS
NL='
'
sep=

while getopts e:f:i opt; do
  case $opt in
    (e) PATTERNS=$PATTERNS$sep$OPTARG; sep=$NL;;
    (f) PATTERNS=$PATTERNS$sep$(cat < "$OPTARG") || exit; sep=$NL;;
    (i) ignorecase='tolower(';;
    (*) usage;;
  esac
done
shift "$((OPTIND - 1))"
if [ -z "$PATTERNS" ]; then
  [ "$#" -gt 0 ] || usage
  PATTERN=$1; shift
fi

[ "$#" -eq 0 ] && exit

exec awk -v q=\' '
  function shquote(s) {
    gsub(q, q "\\" q q, s)
    return q s q
  }
  BEGIN {
    n = split('"$ignorecase"'ENVIRON["PATTERNS"]'"${ignorecase:+)}"', pats, "\n")
    for (arg = 1; arg < ARGC; arg++) {
      file = ARGV[arg]
      cmd = "gzip -dcf < " shquote(file)
      for (i = 1; i <= n; i++) notfound[pats[i]]
      left = n
      while (left && (cmd | getline line) > 0) {
        '"${ignorecase:+line = tolower(line)}"'
        for (pat in notfound) {
          if (line ~ pat) {
            if (!--left) {
              print file
              break
            }
            delete notfound[pat]
          }
        }
      }
      close(cmd)
    }
    exit
  }' "$@"

다음과 같이 사용됩니다:

find ... -exec zgrep-many -ie foo -e bar -e baz {} +

예를 들어.

답변2

grep여러 패턴을 일치시키는 데 AND 옵션은 없지만 기본적으로 OR을 사용하여 패턴을 일치시킬 수 있습니다 |. 확장 구문을 사용하는 경우 여러 패턴과 모든 조합을 결합할 수 있습니다.

a.*b.*c|a.*c.*b|b.*a.*c|b.*c.*a|c.*a.*b|c.*b.*a

하지만 패턴이 2개 이상일 경우 조합 수가 빠르게 늘어나므로 이는 좋은 생각이 아닐 수 있습니다.

zgrep를 사용하여 명령을 결합 할 수 있습니다 -exec. 마지막 옵션을 제외한 -q모든 옵션은 자동 옵션을 사용합니다 zgrep(발견된 모든 이전 grep과 일치하는 경우 파일 이름을 인쇄합니다).

find -mtime -$a -type f ! -name "*.bak*"      \
        -exec zgrep -iq "$b" {} \;            \
        -exec zgrep -iq "$c" {} \;            \
        -exec zgrep -il "$d" {} \; | sort

답변3

find세 개의 -s 를 실행하는 명령을 사용할 수 있습니다 zgrep.

  find -mtime -$a -type f ! -name "*.bak*"      \
       -exec zgrep -q {} "$b" \; \
       -a   -exec zgrep -q {} "$c" \; \
       -a   -exec zgrep -q {} "$d" \; \
    | sort

파일 이름을 먼저 수집할 수도 있습니다 grep.

 find -mtime -$a -type f ! -name "*.bak*" > /tmp/file-list

(파일 이름이 양호하고 공백이 없다고 가정)

그런 다음 각 행을 반복합니다./tmp/file-list

awk마지막으로 다른 언어( Python, ...) 로 스크립트를 작성할 수 있습니다.

입력을 피하기 위해 쉘 함수를 정의할 수 있습니다.

관련 정보