파일에서 전달하는 동안 변수가 awk에서 허용되지 않습니다.

파일에서 전달하는 동안 변수가 awk에서 허용되지 않습니다.

파일을 한 줄씩 읽고 있습니다. 각 줄은 다음과 같습니다.

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

관련 정보