Bash 스크립트: 다른 줄에서 "AND" 조건을 사용하여 텍스트 파일 읽기

Bash 스크립트: 다른 줄에서 "AND" 조건을 사용하여 텍스트 파일 읽기

"AND" 조건을 사용하여 간단한 bash 스크립트를 만들었지만 작동하지 않습니다.

#!/bin/bash

cat log3.txt | \
while read -r LINE
do
  if [[ $LINE =~ Host ]] && [[ $LINE =~ denied ]]  ; then echo $LINE;
fi
done

log3.txt의 내용입니다.

Host: abcd.com
Access denied

OR 조건을 사용하면 잘 작동하지만 AND 조건을 사용하고 싶으므로 로그에 "Host"와 "Access Denied" 문자열이 모두 포함되어 있으면 출력이 표시됩니다.

답변1

루프의 한 반복에서 while값이 $LINE동시에 존재할 수 없습니다.Host 그리고 denied. 파일의 데이터를 고려하면 이는 불가능합니다. 그렇기 때문에 출력을 얻지 못하는 것입니다.

이 두 단어와 일치하는 파일의 모든 줄을 보려면Host 또는 denied, grep대신 다음을 사용하세요.

grep -wF -e 'Host' -e 'Access denied' <log3.txt

여기에 사용된 옵션은 정규식 일치( ) 대신 문자열 비교를 수행하고 하위 문자열( ) -F대신 완전한 단어와 일치하도록 보장합니다. -w두 개의 쿼리 문자열이 주어지면 -e다음을 포함하는 모든 행을 얻습니다.어느이것들.

두 단어가 모두 파일에 나타나는 경우에만 두 단어가 포함된 행만 표시하는 좀 더 고급 쿼리를 수행하려면 프로그램을 사용하여 수행할 수 있습니다 awk.

awk '/Host/ { hostline=$0 } /Access denied/ { deniedline=$0 }
     END { if ((hostline != "") && (deniedline != ""))
               print hostline; print deniedline; }' <log3.txt

여기서 string 과 일치하는 줄을 찾으면 Hoststring 과 동일하게 저장합니다 Access denied. 마지막으로, 두 문자열 모두에 무엇이든 포함되어 있으면 이를 인쇄합니다.

다소 동등한 쉘 코드에서:

#!/bin/sh

while IFS= read -r line; do
    case $line in
        *Host*)
           hostline=$line   ;;
        *"Access denied"*)
           deniedline=$line ;;
    esac
done <log3.txt

if [ -n "$hostline" ] && [ -n "$deniedline" ]; then
    printf '%s\n%s\n' "$hostline" "$deniedline"
fi

case ... esac여기서는 읽은 데이터를 일치시키는 명령문 을 사용합니다 . 사용된 패턴은 정규식이 아닌 파일 이름 와일드카드 패턴입니다.

관련된:

답변2

만약에처리하려는 파일은 작습니다(예제와 같이). 한 번에 전체 파일을 읽고 테스트할 수 있습니다.

 file=$(<log3.txt)
 [[ $file =~ Host ]] && [[ $file =~ denied ]] && echo "$file"

더 큰 파일의 경우 더 빠른(외부 파일의 경우) sed를 사용할 수 있다고 Host가정 합니다.denied

 <log3.txt sed -n '/^Host/!d;p;:1;n;/\<denied\>/{p;q};b1'

Host이 솔루션은 및로 시작하는 첫 번째 줄을 엄격하게 인쇄한다는 점을 이해하십시오 .다음과 같은(같은 라인은 아님)첫 번째단어가 포함된 줄입니다 denied.

추출이 필요한 경우일부Host- 의 경우 a 로 변경되어denied 루프가 다시 시작됩니다.qb

 <log3.txt sed -n '/^Host/!d;p;:1;n;/\<denied\>/{p;b};b1'

awk에 대한 유사한 솔루션은 Host한 줄 앞의 마지막 줄을 denied쌍으로 인쇄합니다.

 awk  '  p==1 && /\<denied\>/     {d=$0;p=0}
                /^Host*/         {h=$0;p=1}
         { if(p==0&&h!=""&&d!="") {print h,RS,d;p=2} }
      '  <log3.txt

논리는 셸에서도 동일합니다( denied단어 대신 행의 어느 위치에서나 일치한다는 점만 제외).

 #!/bin/sh
 p=0
 while IFS= read -r line; do
    if [ "$p" = 1 ]; then
        case $line in
           *denied*)        deniedline=$line; p=0   ;;
        esac
    fi

 case $line in
    Host*)               hostline=$line; p=1   ;;
 esac

 if [ "$p" = 0 ] && [ "$hostline" ] && [ "$deniedline" ]; then
    printf '%s\n%s\n' "$hostline" "$deniedline"
    p=2
 fi

 done <log3.txt

답변3

솔루션이 작동하지 않는 이유를 이해하려면 @Kusalananda의 답변을 참조하세요.

내 솔루션은 다음을 사용합니다 grep -z.

grep -zEo -e 'Host: (\w|\.)+\s+Access denied\s' log.txt

느린:

  • -E: 확장 정규식 사용
  • -o: 일치하는 항목만 인쇄
  • -z\0: 줄 구분 기호 로 사용됩니다 . 문자가 없기 때문에 \n일반 문자 하나만 포함하여 전체 파일에 대해 검색이 수행됩니다.
  • - e'Host: (\w|\.)+\s+Access denied\s': 찾다:
    • " Host:"
    • 문자, 숫자 또는 점의 순서
    • 우주등급 캐릭터 ( \n)
    • " Access denied"
    • 우주급 캐릭터(가 됩니다 \n). 출력에 줄바꿈이 필요합니다.

실행 대상:

Host: denied1.com
Access denied
Host: ok.com
Access OK
Host: random.com

Host: denied2.com
Access denied

More stuff

생산하다:

Host: denied1.com
Access denied
Host: denied2.com
Access denied

관련 정보