developer tip

sed, awk 또는 gawk를 사용하여 일치하는 항목 만 인쇄하는 방법은 무엇입니까?

optionbox 2020. 8. 24. 08:11
반응형

sed, awk 또는 gawk를 사용하여 일치하는 항목 만 인쇄하는 방법은 무엇입니까?


sed, awk 또는 gawk를 사용하여 검색 및 바꾸기와 같은 작업을 수행하는 방법에 대한 많은 예제와 매뉴얼 페이지를 봅니다.

하지만 제 경우에는 특정 값을 추출하기 위해 텍스트 파일에 대해 실행하려는 정규식이 있습니다. 검색 및 바꾸기를 원하지 않습니다. 이것은 bash에서 호출됩니다. 예를 들어 보겠습니다.

정규 표현식의 예 :

.*abc([0-9]+)xyz.*

입력 파일 예 :

a
b
c
abc12345xyz
a
b
c

간단하게 들리지만 sed / awk / gawk를 올바르게 호출하는 방법을 알 수 없습니다. 내가 원하는 것은 bash 스크립트 내에서 다음과 같습니다.

myvalue=$( sed <...something...> input.txt )

내가 시도한 것은 다음과 같습니다.

sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing

sed(Mac OS X)가 +. *대신 시도 하고 p인쇄 일치 태그를 추가했습니다 .

sed -n 's/^.*abc\([0-9]*\)xyz.*$/\1/p' example.txt

없이 하나 이상의 숫자를 일치 시키 +려면 다음을 사용합니다.

sed -n 's/^.*abc\([0-9][0-9]*\)xyz.*$/\1/p' example.txt

sed를 사용하여이 작업을 수행 할 수 있습니다.

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n 결과 라인을 인쇄하지 마십시오
  • -r이렇게하면 캡처 그룹 괄호를 탈출 할 수 없습니다 ().
  • \1 포획 그룹 경기
  • /g 글로벌 경기
  • /p 결과를 인쇄

이 작업을 더 쉽게 만들어주는 도구 를 직접 작성했습니다.

rip 'abc(\d+)xyz' '$1'

나는 perl이것을 더 쉽게 만들기 위해 사용 합니다. 예 :

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'

이것은 Perl을 실행하고이 -n옵션은 Perl이 STDIN에서 한 번에 한 줄씩 읽고 코드를 실행하도록 지시합니다. -e옵션은 실행할 명령을 지정합니다.

이 명령어는 read 행에서 regexp를 실행하고 일치하는 경우 첫 번째 중괄호 ( $1) 세트의 내용을 인쇄합니다 .

당신은 또한 끝에 여러 파일 이름을 할 수 있습니다. 예 :

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt


버전 경우 grep지원을 당신이 사용할 수있는 -o인쇄 옵션을 단지 당신의 정규 표현식 일치하는 모든 라인의 일부를.

그렇지 않다면 여기에 sed내가 생각 해낼 수 있는 최선의 방법이 있습니다 .

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

... 숫자없이 삭제 / 건너 뛰고 나머지 행의 경우 모든 선행 및 후행 숫자가 아닌 문자를 제거합니다. (나는 당신의 의도가 하나를 포함하는 각 줄에서 숫자를 추출하는 것이라고 추측하고 있습니다).

다음과 같은 문제 :

sed -e 's/.*\([0-9]*\).*/&/' 

.... 또는

sed -e 's/.*\([0-9]*\).*/\1/'

... is that sed only supports "greedy" match ... so the first .* will match the rest of the line. Unless we can use a negated character class to achieve a non-greedy match ... or a version of sed with Perl-compatible or other extensions to its regexes, we can't extract a precise pattern match from with the pattern space (a line).


You can use awk with match() to access the captured group:

$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345

This tries to match the pattern abc[0-9]+xyz. If it does so, it stores its slices in the array matches, whose first item is the block [0-9]+. Since match() returns the character position, or index, of where that substring begins (1, if it starts at the beginning of string), it triggers the print action.


With grep you can use a look-behind and look-ahead:

$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345

This checks the pattern [0-9]+ when it occurs within abc and xyz and just prints the digits.


perl is the cleanest syntax, but if you don't have perl (not always there, I understand), then the only way to use gawk and components of a regex is to use the gensub feature.

gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file

output of the sample input file will be

12345

Note: gensub replaces the entire regex (between the //), so you need to put the .* before and after the ([0-9]+) to get rid of text before and after the number in the substitution.


If you want to select lines then strip out the bits you don't want:

egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//'

It basically selects the lines you want with egrep and then uses sed to strip off the bits before and after the number.

You can see this in action here:

pax> echo 'a
b
c
abc12345xyz
a
b
c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//'
12345
pax> 

Update: obviously if you actual situation is more complex, the REs will need to me modified. For example if you always had a single number buried within zero or more non-numerics at the start and end:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

you can do it with the shell

while read -r line
do
    case "$line" in
        *abc*[0-9]*xyz* ) 
            t="${line##abc}"
            echo "num is ${t%%xyz}";;
    esac
done <"file"

For awk. I would use the following script:

/.*abc([0-9]+)xyz.*/ {
            print $0;
            next;
            }
            {
            /* default, do nothing */
            }

gawk '/.*abc([0-9]+)xyz.*/' file

참고URL : https://stackoverflow.com/questions/1733692/how-to-use-sed-awk-or-gawk-to-print-only-what-is-matched

반응형