파일을 한 줄씩 읽고 있습니다. 각 줄은 다음과 같습니다.
xxyu: JHYU_IOPI
각 줄은 아래와 같이 awk로 전달됩니다. 일치하는 패턴의 이전 줄을 인쇄하고 싶습니다. 나는 grep으로 이것을 달성할 수 있고 awk로 어디에서 실수를 했는지 알고 싶습니다.
#!/bin/bash
while read i
do
awk '/$i/{print a}{a=$0}' ver_in.txt
done<in.txt
나는 또한 이것을 시도했다:
#!/bin/bash
while read i
do
awk -v var="$i" '/var/{print a}{a=$0}' jil.txt
done<in.txt
편집: sh 읽기를 사용하지 말라는 제안을 받은 후 awk를 사용합니다. 내 입력과 원하는 출력은 다음과 같습니다.
편집 1: @Ed Morton awk 스크립트의 입력을 아래와 같이 편집했습니다.
입력 파일: cat 파일
/* ----------------- AIX_RUN_WATCH ----------------- */
insert_job: AIX_RUN_WATCH job_type: BOX
owner: root
permission:
date_conditions: 1
days_of_week: su
start_times: "22:00"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 0
notification_emailaddress:
/* ----------------- AIX_stop ----------------- */
insert_job: AIXstop job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 1
/* ----------------- AIX_start ----------------- */
insert_job: AIX_start job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
cat targets
box_name: AIX_RUN_WATCH
예상 출력 -
box_name: AIX_RUN_WATCH
insert_job: AIX_stop
insert_job: AIX_start
답변1
첫 번째 시도에서는 쉘 변수 확장에 큰따옴표를 사용한 다음 awk $
연산자에 대한 인용문을 이스케이프하여 쉘에 의해 확장되는 것을 방지해야 합니다. 그러나 이와 같이 사용하면 변수에 , 와 같은 특수 문자가 포함된 경우 awk가 중단된다는 점에 유의 $i
하십시오 . [지금 귀하의 명령과 관련된 하나 이상의 다른 문제를 해결하기 위해 건너뛰고 있습니다].\
/
while read i
do
awk "/$i/{print a}{a=\$0}" ver_in.txt
done<in.txt
두 번째 시도에서는 정규식 일치(부분 정규식 일치)를 사용하는 것과 같이 현재 행에 대해 정규식 일치 또는 문자열 일치를 사용해야 합니다.
while read i
do
awk -v var="$i" '$0 ~ var{print a}{a=$0}' jil.txt
done<in.txt
또는 다음과 같은 문자열 일치(전체 문자열 일치)입니다.
while read i
do
awk -v var="$i" '$0==var{print a}{a=$0}' jil.txt
done<in.txt
이제 일치하는 패턴의 이전 행을 인쇄하기 위해 사용하려는 명령에 대해 이야기하면 awk로 모든 작업을 수행하고 쉘 루프를 사용하여 중단할 수 있습니다. 여기에서는 전체 문자열 일치를 수행하고 있습니다.
awk 'NR==FNR { str[$0]; next }
($0 in str) && prev!="" { print prev } { prev=$0 }' in.txt ver_in.txt
또는 부분 정규식 일치를 수행합니다.
awk 'NR==FNR { patt[$0]; next }
{ for(ptrn in patt) if($0 ~ ptrn && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
또는 부분 문자열 일치를 수행합니다.
awk 'NR==FNR { strings[$0]; next }
{ for(str in strings) if(index($0, str) && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
또는 전체 정규식 일치를 수행합니다.
awk 'NR==FNR { patt[$0]; next }
{ for(ptrn in patt) if($0 ~ "^"ptrn"$" && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
답변2
이를 위해 while 읽기 루프가 필요하지 않으며 sh에서 텍스트 처리를 수행하는 것은 나쁜 생각입니다(참조쉘 루프를 사용하여 텍스트를 처리하는 것이 나쁜 습관으로 간주되는 이유는 무엇입니까?).
대신 awk 스크립트를 사용하여 두 파일을 모두 처리하세요.
awk 'NR==FNR { re = $0 "|" re ; next}; # append input line and | to re
FNR == 1 { sub(/\|$/,"",re) }; # remove trailing | on 1st line of 2nd file
$0 ~ re { print a }; # if the current line matches re, print a
{a = $0}' in.txt ver_in.txt
첫 번째 파일( )을 읽는 동안 각 입력 줄과 정규식 "대체"를 추가하여 in.txt
호출되는 변수에 정규식을 구성합니다 (예:re
또는) 운영자.
첫 번째 파일 읽기가 끝나면 가장 먼저 해야 할 |
일은 re
. re
그럴 것이기 때문에 이것은 필요하다언제나|
구성 방식으로 인해 성격이 생깁니다 . 이를 제거하지 않으면 해당 후행으로 |
인해 정규 표현식이 ver_in.txt
.
그 후, a
현재 입력 줄이 변수의 정규식과 일치하면 변수를 인쇄합니다 re
(ver_in.txt의 첫 번째 줄이 일치하면 a가 비어 있기 때문에 빈 줄이 인쇄됩니다 re
. 그런 일이 발생하지 않도록 하려면 해당 줄을 다음에서 변경하세요). $0 ~ re {print a}
에게 $0 ~ re && a != "" {print a}
).
그런 다음 일치 여부에 관계없이 를 설정합니다 a=$0
.
참고: 이는 NR==FNR {... ; next}
첫 번째 입력 파일을 두 번째 및 후속 입력 파일과 다른 방식으로 처리하기 위한 매우 일반적인 awk 관용어입니다. NR
는 읽고 있는 모든 파일에 대한 전역 라인 카운터이고 FNR
현재 파일에 대한 라인 카운터입니다....그래서 이면 NR==FNR
첫 번째 파일을 읽고 있다는 뜻입니다. 이 next
명령문은 다음 입력 줄로 건너뛰어 첫 번째 파일에 있는 동안 awk 스크립트의 나머지 부분이 실행되지 않도록 합니다.
완전한 데이터 샘플을 제공하지 않았기 때문에 직접 테스트하기 위해 다음을 만들었습니다.
$ cat in.txt
xxyu: JHYU_IOPI
foo
bar
이 in.txt 파일은 re를 동일하게 만듭니다.bar|foo|xxyu: JHYU_IOPI
그런데, awk 스크립트가 정규식 일치를 수행하기 때문에 re
의 줄은 in.txt
고정 텍스트가 아닌 정규식으로 처리됩니다. 즉, in.txt의 정규식 특수 문자(예 .
: |
, [
또는 ]
기타 여러 문자)를 리터럴 문자로 처리하려면 백슬래시를 사용하여 이 문자를 이스케이프 처리해야 합니다. 원래 sh+awk 루프에도 적용됩니다.
$ cat ver_in.txt
a line 1
xxyu: JHYU_IOPI
b line 3
d line 4
bar
e line 6
f line 7
foo
위 awk 스크립트의 출력:
a line 1
d line 4
f line 7
답변3
텍스트를 조작하기 위해 쉘 루프를 사용하지 마십시오.쉘 루프를 사용하여 텍스트를 처리하는 것이 나쁜 습관으로 간주되는 이유는 무엇입니까?. 쉘을 발명한 사람들은 텍스트를 조작하기 위해 쉘을 호출하기 위한 awk도 발명했습니다.
모든 Unix 상자의 모든 쉘에서 awk를 사용하십시오.
$ cat tst.awk
NR==FNR {
tgts[$0]
next
}
$0 in tgts {
if ( $0 != prevTgt ) {
print $0
prevTgt = $0
}
print prevLine
}
{ prevLine = $1 FS $2 }
$ awk -f tst.awk targets file
box_name: AIX_RUN_WATCH
insert_job: AIXstop
insert_job: AIX_start
원래 답변:
awk '
BEGIN { RS=""; FS="\n" }
$2 != prev {
print $2
prev = $2
}
{ print $1 }
' file
ght: ertyjk
xxx: rtyuiol
xxx: ertyuikl_fghjk
xxx: qwertyujkl
xxx: rtyuiol_123
ght: YUIOPO
xxx: rtyuiol
xxx: rtyuiopfghj
xxx: dfghjkvbnm
xxx: qzdfghnbvfgh
xxx: qsxcvghuiokmnhgf
보다https://www.gnu.org/software/gawk/manual/gawk.html#Multiple-LineRS를 null로 설정하면 여러 줄의 레코드로 작업할 수 있고, FS를 개행으로 설정하면 해당 레코드의 각 필드가 전체 라인이므로 데이터를 빈 줄로 구분된 레코드로 처리한다는 의미입니다. 2줄의 데이터가 포함되어 있습니다.
인쇄해야 할 항목을 나타내는 다른 ght 행 파일이 있다고 언급했는데, 이는 인쇄하면 안 되는 다른 블록이 있음을 의미합니다. 해당 파일이 있고 다음과 같은 경우:
$ cat targets
ght: ertyjk
ght: YUIOPO
다른 입력 파일에는 ght:
위와 일치하지 않는 일부 줄이 포함되어 있습니다. 예를 들어 ght: whatever
아래 수정된 입력 파일의 블록을 참조하세요.
$ cat file
xxx: rtyuiol
ght: ertyjk
xxx: ertyuikl_fghjk
ght: ertyjk
xxx: qwertyujkl
ght: ertyjk
xxx: rtyuiol_123
ght: ertyjk
xxx: foo
ght: whatever
xxx: bar
ght: whatever
xxx: rtyuiol
ght: YUIOPO
xxx: rtyuiopfghj
ght: YUIOPO
xxx: dfghjkvbnm
ght: YUIOPO
xxx: qzdfghnbvfgh
ght: YUIOPO
xxx: qsxcvghuiokmnhgf
ght: YUIOPO
그러면 위 코드는 다음과 같이 업데이트됩니다.
awk '
BEGIN { FS="\n" }
NR==FNR {
tgts[$0]
next
}
$2 != prev {
if ( inTgts = ($2 in tgts) ) {
print $2
}
prev = $2
}
inTgts { print $1 }
' targets RS='' file
ght: ertyjk
xxx: rtyuiol
xxx: ertyuikl_fghjk
xxx: qwertyujkl
xxx: rtyuiol_123
ght: YUIOPO
xxx: rtyuiol
xxx: rtyuiopfghj
xxx: dfghjkvbnm
xxx: qzdfghnbvfgh
xxx: qsxcvghuiokmnhgf