![Bash 스크립트: 다른 줄에서 "AND" 조건을 사용하여 텍스트 파일 읽기](https://linux55.com/image/142954/Bash%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%3A%20%EB%8B%A4%EB%A5%B8%20%EC%A4%84%EC%97%90%EC%84%9C%20%22AND%22%20%EC%A1%B0%EA%B1%B4%EC%9D%84%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20%ED%85%8D%EC%8A%A4%ED%8A%B8%20%ED%8C%8C%EC%9D%BC%20%EC%9D%BD%EA%B8%B0.png)
"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 과 일치하는 줄을 찾으면 Host
string 과 동일하게 저장합니다 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
루프가 다시 시작됩니다.q
b
<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