파일에서 전달될 때 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 read를 사용하지 말라는 조언을 받은 후 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

이를 위해 읽는 동안 루프가 필요하지 않으며 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 파일은 다음과 같습니다.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

관련 정보