쉘 변수를 awk에 / pattern /으로 전달하십시오.


59

내 쉘 함수 중 하나에 다음이 포함됩니다.

function _process () {
  awk -v l="$line" '
  BEGIN {p=0}
  /'"$1"'/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '
}

그래서으로 전화했을 때 _process $arg, $arg로 전달됩니다 $1및 검색 패턴으로 사용. 쉘 $1이 awk 패턴 대신 확장되기 때문에 이런 식으로 작동합니다 ! 또한 l, AWK 프로그램 내에서 사용할 수있는 선언되고 -v l="$line". 다 괜찮아

같은 방식으로 패턴을 변수로 검색 할 수 있습니까?

다음은 작동하지 않습니다.

awk -v l="$line" -v search="$pattern" '
  BEGIN {p=0}
  /search/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '

awk는 /search/변수로 해석되지 않고 문자 그대로 해석합니다.

답변:


46

awk의 ~연산자를 사용 하면 오른쪽에 리터럴 정규식을 제공 할 필요가 없습니다.

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1} 
        END {if(p) print l >> "outfile.txt"}
    '  
}

이것이 더 효율적이지만 (전체 파일을 읽을 필요는 없습니다)

function _process () {
    grep -q "$1" && echo "$line"
}

패턴에 따라 원하는 경우가 있습니다 grep -Eq "$1"


이것이 의미를 유지하기 때문에 내가 원하는 방식 으로이 문제를 해결하는 것입니다 (첫 번째 예). 이것이 내 목표였습니다. 감사.
branquito

1
BEGIN 블록 제거에 대해서는 언급하지 않았습니다. 할당되지 않은 변수는 숫자 컨텍스트에서 0으로 처리되거나 그렇지 않으면 빈 문자열로 처리됩니다. 따라서 할당되지 않은 변수는 다음과 같습니다.if (p) ...
glenn jackman

예, 스위치 역할을하므로 BEGIN 블록에서 매번 0으로 설정해야합니다. 그러나 흥미롭게도을 사용하여 스크립트를 시도했지만 $0 ~ pattern작동하지 않지만 작동 /'"$1"'/합니다!? : O
branquito

어쩌면이 길을 함께 할 수있는 뭔가가 $line검색되어, 패턴 검색의 출력에서 수행되고 whois $line, $line블록 DO 한 동안 파일에서 오는.
branquito

$line올바른 형식을 위해 질문에 내용을 표시하십시오 .
glenn jackman

17
awk  -v pattern="$1" '$0 ~ pattern'

awk에서 ANSI C 이스케이프 시퀀스 (예 \n: 줄 바꿈, \f양식 피드, \\백 슬래시 등) 를 확장 하는 문제 가 $1있습니다. 따라서 $1정규 표현식에서 공통적 인 백 슬래시 문자가 포함되어 있으면 문제가됩니다 (GNU awk4.2 이상에서는으로 시작 @/하고 끝나는 값 /도 문제가됩니다 ). 이 문제로 어려움을 겪지 않는 또 다른 접근법은 다음과 같이 작성하는 것입니다.

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'

그것이 얼마나 나쁜지는 awk구현에 달려 있습니다 .

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo

awk유효한 이스케이프 시퀀스에 대해 모든 것이 동일하게 작동합니다.

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000   \   \   -   \   b  \n
0000006

( $a통과 그대로 내용 )

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000   \   -  \b  \n
0000004

( \\변경 \\b백 스페이스 문자로 변경).


\d{3}를 들어 패턴이 예 를 들어 세 자리를 찾는 경우 잘 이해하면 예상대로 작동하지 않는다고 말하는 것입니까?
branquito

2
에 대해 \d어떤 유효한 C 탈출 당신에 따라 순서 아닌 awk구현 (실행 awk -v 'a=\d{3}' 'BEGIN{print a}'확인). 그러나 \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d`는 숫자를 의미합니다.
Stéphane Chazelas

그것은 awk warning-escape sequence \d' treated as plain d 'd {3} 이라고 말하는데 ,이 경우에 문제가 있다고 생각합니까?
branquito

1
미안, 내 나쁜, 나는 내 대답에 오타가있었습니다. 그때 환경 변수의 이름은 환경 변수와 일치 ENVIRON["PATTERN"]해야합니다 PATTERN. 쉘 변수를 사용하려면 먼저 변수를 내보내 export variable거나 ( ) ENV=VALUE awk '...ENVIRON["ENV"]'내 대답과 같이 env-var 전달 구문을 사용해야합니다 .
Stéphane Chazelas

1
환경에서 쉘 변수를 명령으로 전달하려면 쉘 변수를 내 보내야합니다.
Stéphane Chazelas

5

다음과 같은 것을 시도하십시오 :

awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'

이것이 /regex/패턴 찾기 측면에서 와 동일하게 작동 하면 좋은 해결책이 될 수 있습니다. 노력하겠습니다.
branquito

1
내가 실행 한 빠른 테스트는 동일하게 작동하는 것 같지만 보장조차하지 않습니다 ... :)
Hunter Eidson

0

아니요, 그러나 awk에 전달하는 큰 따옴표로 묶은 문자열에 패턴을 보간 할 수 있습니다.

awk -v l="$line" "BEGIN {p=0}; /$pattern/ {p=1}; END{ if(p) print l >> \"outfile.txt\" }"

큰 따옴표로 묶인 awk 리터럴을 이스케이프해야하지만 여전히 가장 간단한 방법입니다.


$pattern공백 이 포함되어 있으면이 방법이 안전합니까? 위의 예는 $ 1이 "$ 1"큰 따옴표로 보호되어 있지만 귀하의 경우에는 어떤 일이 발생하는지 확실하지 않습니다.
branquito

2
원래 예제는 초에 작은 따옴표로 묶인 문자열을 끝내고 via 큰 따옴표 '를 보호 $1한 다음 awk 프로그램의 후반에 대해 작은 따옴표로 묶인 다른 문자열을 가져옵니다. 올바르게 이해 $1하면 외부 작은 따옴표를 통해 via 를 보호하는 것과 정확히 동일한 효과를 가져야합니다. awk는 주위에 큰 따옴표를 보지 않습니다.
Kilian Foth

4
그러나가 $pattern포함되어 있으면 ^/ {system("rm -rf /")};큰 어려움에 처한 것입니다.
Stéphane Chazelas

이 접근 방식의 단점은 모두 ""로 감싼 것입니까?
branquito

-3

이 예제에서 awk가 실행되기 전에 nets 변수를 해결하는 eval 함수를 사용할 수 있습니다.

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.