변수에 저장된 특정 줄 번호에서 awk를 실행하는 방법

변수에 저장된 특정 줄 번호에서 awk를 실행하는 방법

bar발생 후 첫 번째 발생의 줄 번호를 얻고 싶습니다 foo.

이는 while전체 파일에 대해 루프로 실행되어야 합니다. 이와 같이:

테스트 파일:

bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
bar foo
xxx
xxx
xxx
xxx
xxx
bar

bar나는 다음을 찾아야 foo하지만 첫 번째 것과 같은 줄에 있지 않습니다 foo. 다음과 같은 것이 있으면 bar foo찾고 싶습니다. 15번째 줄을 찾을 수 없습니다.

다음을 반환해야 합니다.

linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21

내 코드:

linenumbersfoo=($(awk '/foo/ {print FNR}' test_file.sh))
length="${#linenumbersfoo[@]}"

while [[ $COUNTERR -lt length  ]]; do
number=$((${linenumbersfoo["$COUNTERR"]}))

linenumbersbar[$COUNTERR]=$(awk '"$number"<=NR, /bar/ {print FNR;exit;}' test_file.sh)

let COUNTERR=COUNTERR+1 
done

echo "${linenumbersfoo[@]}"

echo "${linenumbersbar[@]}"

나는 얻다:

linenumbersfoo: 1 12
linenumbersbar: 1 1

문제는 변수인 것 같습니다 . 예를 들어 대신 number쓰면 작동합니다.5$number

어떤 도움이라도 대단히 감사하겠습니다!

답변1

이 필드는 foo이 필드와 함께 나타나므로 bar매우 명확한 알고리즘을 만들 수 있습니다.

awk '/bar/ {A[NR]=0} /foo/ {A[NR]++} END {for(i in A) print i,A[i]}' file
1 1
5 0
6 0
8 0
12 1
15 1
21 0

두 번째 열을 이동하면 1 - true 및 0 - fals를 표시하는 행 번호를 얻을 수 있습니다.

1 
5 1
6 0
8 0
12 0
15 1
21 1
   0

해보자:

awk '/bar/ {A[NR]=0} /foo/ {A[NR]++} END {for(i in A) {if(A[l]) print i; l = i}}' file
5
15
21

승리! 첫 번째 줄을 표시하고 이를 원하는 형식(포맷된 출력)으로 변환합니다.

awk '
BEGIN   {printf "linenumbersfoo:"}
/bar/   {A[NR]=0}
/foo/   {A[NR]++; printf FS NR} 
END     {printf "\nlinenumbersbar:"
        for(i in A) {if(A[l]) printf FS i
                l = i}
                print ""
        }
' file
linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21

답변2

편집: 편집 내용과 일치하도록 개선 사항을 추가하십시오...

awk에 대한 제안:

BEGIN {
  ffoo=0; ffoos=""; fbars="";
} 
/foo/ {
  ffoo=1; ffoos=ffoos" "NR;
} 
/bar/ {
  if ((match($0, "foo") == 0) && (ffoo!=0)) {
    fbars=fbars" "NR; 
    ffoo=0;
  }
} 
END {
  print "linenumbersfoo: "ffoos"\n"; 
  print "linenumbersbar: "fbars"\n";
}

답변3

쉘 루프에서 이 작업을 수행하지 마십시오 awk. 우리가 대신 수행합니다.

다음은 awk스크립트 파일에 저장하고 호출할 수 있는 스크립트 입니다 awk -f script.awk filename(질문의 가장 최근 편집 내용과 함께 작동하도록 수정됨).

BEGIN {
        follows["foo"] = "bar"
        follows["bar"] = "foo"
}

{
        for (i = 1; i <= NF; ++i)
                if (lookfor == "") {
                        if ($i in follows)
                                lookfor = follows[$i]
                } else if ($i == lookfor) {
                        record[$i] = (record[$i] == "" ? "" : record[$i] OFS ) FNR
                        lookfor = follows[$i]
                }
}

END {
        for (i in record)
                printf "%s:\t%s\n", i, record[i]
}

샘플 데이터에서 실행:

$ awk -f script.awk file
foo:    1 12 15
bar:    5 15 21

이 스크립트는 연관 목록을 설정합니다 follows. 목록에는 foo찾으면 찾아야 bar하고, bar찾으면 foo다시 찾는 데 관심이 있음을 보여줍니다.

스크립트 awk는 에서 문자열을 찾습니다 lookfor. 처음에는 배열에서 키를 찾은 follows다음 해당 배열을 사용하여 lookfor다음에 찾을 문자열을 설정합니다. 찾고 있는 문자열을 찾을 때마다 record해당 문자열의 연관 배열에 현재 줄 번호를 저장합니다.

마지막으로 record수집된 라인 번호가 출력됩니다.

스타일리시한 라인

record[$i] = (record[$i] == "" ? "" : record[$i] OFS ) FNR

배열의 줄 번호 문자열 끝에 줄 번호를 추가합니다 record. 문자열이 비어 있으면 현재 줄 번호로만 설정되지만, 이미 포함되어 있는 경우에는 기존 문자열과 줄 번호 사이에 쉼표가 삽입됩니다.

답변4

~을 위한부자:

for i in `awk '/foo/{print NR}' filename`; do sed -n "$i,/bar/{;=;p}" filename|sed "N;s/\n/ /g"| awk '/foo|bar/'; done|awk '/bar/{print $1}'|perl -pne "s/\n/ /g"| awk '{print "linenumbersfoo: "$0}'

산출:

linenumbersfoo: 1 12 

~을 위한술집:

for i in `awk '/foo/{print NR}' filename`; do sed -n "$i,/bar/{;=;p}" o1|sed "N;s/\n/ /g"| awk '/foo|bar/'; done|awk '/bar/{print $1}'|perl -pne "s/\n/ /g"| awk '{print "linenumbersfoo: "$0}'

산출:

linenumbersbar: 5 18 

관련 정보