sed, awk 또는 grep을 사용하여 각 줄에서 여러 패턴을 추출하는 방법

sed, awk 또는 grep을 사용하여 각 줄에서 여러 패턴을 추출하는 방법

다음과 같은 텍스트 파일이 있습니다.

tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample

샘플 텍스트를 추출하고 싶습니다 - 다음과 같은 단어과학 기술그리고 이와 같은 숫자 패턴7.5및 기타 디지털 모드.

(실제로 숫자 패턴은 버전 제어 스타일 버전 번호입니다)

그런 다음 다음과 같이 출력을 얻습니다.

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

답변1

가설

입력은 공백 문자 시퀀스(공백이 아닌 문자 시퀀스)로 구분된 문자열을 포함하는 텍스트 파일입니다. 각 줄에는 특정 단어(런타임에 알려짐)가 포함되어 있으며 그 뒤에는 버전 번호 형식의 숫자 문자열이 옵니다(즉시 필요하지는 않음). (분명히 이는 숫자로 시작한다는 의미입니다.)

런타임에 인수로 찾을 단어를 지정할 수 있어야 합니다. 예를 들어, 다음 단어를 검색하려면과학 기술, 우리는 말할 수 있어야합니다

word=tech

명령(또는 스크립트)이 를 사용하도록 합니다 $word. 예를 들어 "technology", "nanotech" 및 "Tech"는 일치하지 않아야 합니다. 단어에는 문자, 숫자 및 _(밑줄)(구두점, 정규 표현식의 특수 문자)만 포함되어야 하며 이로 인해 원치 않는 결과가 발생할 수 있습니다. 각 한정된 줄에 대해 명령은 공백으로 구분된 단어와 숫자를 출력해야 합니다. 파일에 이러한 가정을 충족하지 않는 줄이 포함되어 있으면(예: 필수 단어나 숫자가 포함되어 있지 않음) 동작이 정의되지 않습니다. 특히, 이러한 실패 라인은 간단히 무시할 수 있습니다.

아래의 모든 명령 $word은 위와 같이 정의된 것으로 가정합니다.

참고: 이러한 각 명령은 서로 다른 방식으로 표현될 수 있습니다. 어떤 경우에는 그 차이가 미미합니다.

grep

분명히grep

나는 무엇을 해야할지 모르겠습니다.

간단 grep하고 도움이 됨

주문하다

grep    "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"

다음을 포함하는 모든 줄과 일치합니다.누구나단어( \<$word\>) 또는 ( \|) 숫자( \<[[:digit:]][[:graph:]]*\>). ( [[:graph:]]문자, 숫자 또는 구두점, 즉 공백을 제외한 모든 문자를 나타냅니다.) --color모드에서 이 명령의 출력은 약간 흥미롭습니다.

        컬러 grep 출력

grep -o "\<$word\>\|\<[[:digit:]][[:graph:]]*\>"

일치하는 모든 문자열을 인쇄하고 일치하는 문자열만 인쇄합니다.— 별도의 줄에:

tech
1.2
tech
1
tech
0.1
tech
10.1.3
tech
7.5
tech
8.0
tech
0.x
tech
1.3.x
tech
5.x
tech
2.0.4x

그럼 우리는 이렇게 해요

grep -o "\<$word\>\|\<[[:번호:]][[:Graphic:]]*\>"(입력 파일)| sed "/$단어/ { N; s/\n/ / }"
위의 출력을 얻고 단어를 연결합니다(과학 기술) 및 다음 줄(공백으로 구분):

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

pcregrep

pcregrep -o1 -o2 --om-separator=' ' "\b($word)\b.*?\b(\d\S*)"

단어를 일치그리고숫자( \b단어 경계, \d숫자, 공백을 제외한 모든 문자)는 ... 그룹 \S에서 각각을 캡처합니다 . 그런 다음 일치하는 문자열만 출력 합니다 . 그러나 에서는 출력 캡처 그룹 1과 2 라고 말할 수 있습니다 . 당연히 문자열 사이에 무엇을 넣을지 지정하세요.()-opcregrep-o1 -o2--om-separator=' '

참고: 여기서는 (탐욕적이지 않은 일치)를 사용하므로 .*?입력 줄에 여러 숫자가 있는 경우 첫 번째 숫자가 검색됩니다. 다른 명령은 마지막 명령을 찾습니다.

sed

sed -n "s/.*\(\<$word\>\).*[[:blank:]]\(\<[[:digit:]][[:graph:]]*\).*/\1 \2/p"

해당 명령과 유사하게 pcregrep이 명령은 캡처 그룹의 문자열을 일치시킨 다음 이를 \1 \2.

awk

awk -v the_word="$word" '
    {
        w=0             # Index of word
        n=0             # Index of number
        for (i=0; i<=NF; i++) {
                if ($i == the_word) w=i
                if (substr($i,1,1) ~ /[[:digit:]]/) n=i
        }
        if (w>0  &&  n>w) print $w, $n
    }'

the_word그러면 단어( )와 숫자(첫 번째 문자가 숫자인 문자열)를 찾습니다 . 찾으면 순서대로 인쇄합니다.

참고: 단어는 완전히 독립된 경우에만 인식됩니다. 구두점에 도달하면 다른 명령도 이를 일치시킵니다.

The cyber clock goes tech, tock …
This contains the word (tech) …

답변2

아래 코드는 원하는 효과를 달성해야 합니다.

searchword="tech"
(cat << EOF
tech -this is sample and ... 1.2 sample
bla bla bla test tech 1 one two
foo bar foo bar tech and [email protected] 0.1
bar bar bar foo foo tech 10.1.3
tech 7.5 and continue this line
sample_test one two tech 8.0
one two there tech 0.x *sample bla bla
www sample tech 1.3.x foo bar $foo #bar
foobar barbar bla bla tech 5.x
tech testtest 2.0.4x this is sample
EOF
) | grep $searchword |\
grep -o '\b[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9x][0-9x]*\b\|\b[0-9][0-9]*\.[0-9][0-9]*\.[0-9x][0-9x]*\b' |\
sed "s/^/$searchword /"

당신을 데려올 것이다

tech 1.2
tech 1
tech 0.1
tech 10.1.3
tech 7.5
tech 8.0
tech 0.x
tech 1.3.x
tech 5.x
tech 2.0.4x

적어도

  • 세게 때리다GNU bash, version 4.4.5(1)-release
  • sedsed (GNU sed) 4.2.2
  • grepgrep (GNU grep) 2.27

이 답변이 도움이 되어 다행입니다. 그렇지 않으면 질문을 더 명확하고 설명하기 쉽게 고려할 수 있을 것입니다.

답변3

grep이나 sed에서는 이것을 얻을 수 없지만 Perl이 도움을 줍니다:

$ perl -e 'while($stdin = <>) {@matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g; print "@matches\n" if @matches}' < INPUTFILE

이는 < INTPUTFILEstdin을 통해 스크립트에 파일을 입력할 때만 작동합니다. stdin은 다른 소스(예: 파이프, <<<문자열 리디렉션)에서 제공될 수 있습니다.

설명하다:

# 일치에 사용할 변수에 표준 입력(Perl)을 할당합니다.
# 입력이 비어 있는 경우(예: EOF)를 감지합니다.
동안 ($stdin = ) {
    # @matches 배열에 $stdin에 일치 항목을 할당합니다.
    #/(기술)[^0-9]*([0-9x][0-9x.]*)/g;
    # (tech): "tech"라는 용어와 일치하고, ()는 @matches에 넣습니다.
    # [^0-9]*: .*가 너무 탐욕스럽기 때문에 숫자가 아닌 숫자와 일치하면 버려집니다.
    # 마지막 숫자와 일치
    # ([0-9x][0-9x.]*): 0, 0.x, 0.9.x 등의 패턴을 일치시키고 () @matches에 넣습니다.
    @matches = $stdin =~ /(tech)[^0-9]*([0-9x][0-9x.]*)/g;
    # @matches가 비어 있지 않으면 위 배열을 표시합니다.
    @matches이면 "@matches\n"을 인쇄합니다.
}

파일에 적용하면 출력은 다음과 같습니다.

기술 1.2
기술 1
기술 0.1
기술 10.1.3
기술 7.5
기술 8.0
기술 1.3.x
기술 5.x
기술 2.0.4x

관련 정보