sed / grep을 사용하여 두 단어 사이의 텍스트를 추출하는 방법은 무엇입니까?


134

문자열의 두 단어 사이에있는 모든 것을 포함하는 문자열을 출력하려고합니다.

입력:

"Here is a String"

산출:

"is a"

사용 :

sed -n '/Here/,/String/p'

엔드 포인트를 포함하지만 포함하고 싶지 않습니다.


8
입력 값이 Here is a Here String어떤 경우 결과는 무엇입니까? 아니면 I Hereby Dub Thee Sir Stringy?
ghoti

5
참고로 명령은 Here라는 단어가있는 줄과 String이라는 단어가있는 줄 사이의 모든 것을 인쇄하는 것을 의미합니다.
Hai Vu

다른 일반적인 sedFAQ는 "특정 행 사이에서 텍스트를 추출하는 방법"입니다. 이것은 stackoverflow.com/questions/16643288/…
5

답변:


109
sed -e 's/Here\(.*\)String/\1/'

2
감사! "여기서 하나는 문자열입니다"에서 "하나"와 "문자열"사이의 모든 것을 찾으려면 어떻게해야합니까? (sed -e 's / one is (. *) String / \ 1 /'?
user1190650

5
@ user1190650 "Here is a"를보고 싶다면 작동합니다. 테스트 할 수 있습니다 : echo "Here is a one is a String" | sed -e 's/one is\(.*\)String/\1/'. "one is"와 "String"사이의 부분 만 원한다면 정규식을 전체 줄과 일치시켜야합니다 sed -e 's/.*one is\(.*\)String.*/\1/'. sed에서 s/pattern/replacement/"각 라인의 '패턴'을 '대체'로 바꾸십시오. "라고 말합니다. "패턴"과 일치하는 항목 만 변경하므로 전체 줄을 바꾸려면 "패턴"을 전체 줄과 일치시켜야합니다.
브라이언 캠벨

9
입력이 다음과 같은 경우에 끊어짐Here is a String Here is a String
Jay D

1
사례에 대한 해결책을 살펴보면 좋을 것입니다. "여기서 blah blah 문자열이 있습니다. 여기에 1 blah blah 문자열이 있습니다. 여기에 2 개의 blash blash 문자열이 있습니다"출력은 Here와 String 사이의 첫 번째 하위 문자열 만 선택해야합니다. "
Jay D

1
@JayD sed는 욕심없는 매칭을 지원하지 않습니다 . 권장되는 대안 은 이 질문 을 참조하십시오 .
Brian Campbell

180

GNU grep은 긍정적 & 부정적 예측 및 예측을 지원할 수 있습니다. 귀하의 경우 명령은 다음과 같습니다.

echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'

Hereand 가 여러 번 나타나는 경우 string처음 Here부터 마지막 까지 string일치시킬 것인지 개별적으로 일치시킬 것인지 선택할 수 있습니다 . 정규 표현식의 관점에서 욕심 일치 (첫 번째 경우) 또는 욕심없는 일치 (두 번째 경우)라고합니다.

$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*(?=string)' # Greedy match
 is a string, and Here is another 
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*?(?=string)' # Non-greedy match (Notice the '?' after '*' in .*)
 is a 
 is another 

31
GNU grep의 -P옵션은 grep* BSD에 포함되어 있거나 SVR4 (Solaris 등)와 함께 제공되는 옵션에는 없습니다 . FreeBSD에서는 PCRE를 지원 하는 devel/pcre포트 pcregrep(및 미리보기 / 뒤) 를 포함 하는 포트를 설치할 수 있습니다 . 이전 버전의 OSX는 GNU grep을 사용했지만 OSX Mavericks에서는 -PFreeBSD의 버전에서 파생되었으며 옵션이 포함되어 있지 않습니다.
ghoti

1
안녕하세요, 어떻게 다른 콘텐츠 만 추출합니까?
Durgesh Suthar

4
종료 문자열 "string"이 두 번 이상 발생하면 다음 발생이 아닌 마지막 발생 을 얻으므로 작동하지 않습니다 .
Buttle Butkus

6
의 경우 Here is a string a string, 모두 " is a " 와이 " is a string a "문제의 요구 사항에 따라 유효한 응답 (따옴표를 무시)이다. 당신이 원하는 것 중 하나에 따라 달라지며 그에 따라 대답이 다를 수 있습니다. 어쨌든, 귀하의 요구 사항에 대해 다음과 같이 작동합니다.echo "Here is a string a string" | grep -o -P '(?<=Here).*?(?=string)'
anishsane

2
@BND, pcregrep의 여러 줄 검색 기능 을 활성화해야합니다 . echo $'Here is \na string' | grep -zoP '(?<=Here)(?s).*(?=string)'
anishsane

58

허용 된 답변은 이전 Here또는 이후에 있을 수있는 텍스트를 제거하지 않습니다 String. 이것은 :

sed -e 's/.*Here\(.*\)String.*/\1/'

주된 차이는 첨가이다 .*직전 Here후의 String.


당신의 대답은 유망합니다. 하나의 문제. 같은 줄에 여러 문자열이있는 경우 첫 번째 문자열로 추출하려면 어떻게해야합니까? 감사합니다
Mian Asbat Ahmad

@MianAsbatAhmad 당신은 만들고 싶어 할 *사이에, 정량을 Here하고 String, 비 - 욕심 (또는 게으른). 그러나 sed에서 사용하는 정규식 유형은 Stackoverflow 질문 에 따라 게으른 수량 자를 ?즉시 지원하지 않습니다 . 일반적으로 게으른 수량자를 구현하려면 일치하지 않으려는 토큰을 제외한 모든 항목과 일치하지만이 경우 단일 토큰이 아니라 전체 문자열 인 경우가 있습니다. .*String
휠러


문자열에 줄 바꿈이 있으면 불행히도 작동하지 않습니다
Witalo Benicio

해서는 안됩니다. .줄 바꿈과 일치하지 않습니다. 줄 바꿈을 일치 시키려면 .다음과 같이 바꿀 수 있습니다 [\s\s].
wheeler

35

Bash 에서만 문자열을 제거 할 수 있습니다 .

$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ echo "$foo"
is a
$

그리고 PCRE 가 포함 된 GNU grep이 있으면 너비가 0 인 어설 션을 사용할 수 있습니다.

$ echo "Here is a String" | grep -Po '(?<=(Here )).*(?= String)'
is a

이 방법이 왜 그렇게 느린가? 이 방법을 사용하여 큰 HTML 페이지를 제거 할 때 10 초 정도 걸립니다.
Adam Johns

@AdamJohns, 어떤 방법? PCRE 하나? PCRE는 구문 분석이 상당히 복잡하지만 10 초가 극단적 인 것 같습니다. 우려되는 경우 예제 코드를 포함 하여 질문제기 하고 전문가의 의견을 참조하십시오.
ghoti

변수에 매우 큰 html 파일의 소스를 보유하고 있었기 때문에 너무 느리다고 생각합니다. 파일에 내용을 쓰고 파일을 파싱하면 속도가 크게 증가했습니다.
Adam Johns

22

GNU awk를 통해

$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
 is a 

grep -P( perl-regexp ) 매개 변수 support \K를 사용하면 이전에 일치 한 문자를 버리는 데 도움이됩니다. 이 경우 이전에 일치 한 문자열이 Here최종 출력에서 ​​삭제되었습니다.

$ echo "Here is a string" | grep -oP 'Here\K.*(?=string)'
 is a 
$ echo "Here is a string" | grep -oP 'Here\K(?:(?!string).)*'
 is a 

출력을 원하면 is a아래를 시도해보십시오.

$ echo "Here is a string" | grep -oP 'Here\s*\K.*(?=\s+string)'
is a
$ echo "Here is a string" | grep -oP 'Here\s*\K(?:(?!\s+string).)*'
is a

이것은 작동하지 않습니다 : echo "Here is a string dfdsf Here is a string" | awk -v FS="(Here|string)" '{print $2}', is a대신 is a is a@Avinash Raj 이어야합니다.
alper

20

여러 줄로 된 사건이 ​​많은 긴 파일이 있으면 먼저 번호 줄을 인쇄하는 것이 좋습니다.

cat -n file | sed -n '/Here/,/String/p'

3
감사! 이것은 내 경우에 작동 한 유일한 솔루션입니다 (줄 바꿈이없는 단일 문자열이 아닌 여러 줄 텍스트 파일). 분명히, 줄 번호를 지정하지 않으려면 -nin 옵션을 cat생략해야합니다.
Jeffrey Lebowski

...이 경우 cat완전히 생략 할 수 있습니다. sed파일 또는 표준 입력을 읽는 방법을 알고 있습니다.
tripleee

9

이것은 당신을 위해 일할 수 있습니다 (GNU sed) :

sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file 

이것은 개행 에서 두 개의 마커 (이 경우 HereString) 사이에 각 텍스트 표현을 제시 하고 텍스트 내에 개행을 유지합니다.


7

위의 모든 솔루션에는 마지막 검색 문자열이 문자열의 다른 곳에서 반복되는 결함이 있습니다. bash 함수를 작성하는 것이 가장 좋습니다.

    function str_str {
      local str
      str="${1#*${2}}"
      str="${str%%$3*}"
      echo -n "$str"
    }

    # test it ...
    mystr="this is a string"
    str_str "$mystr" "this " " string"

6

두 개의 s 명령을 사용할 수 있습니다

$ echo "Here is a String" | sed 's/.*Here//; s/String.*//'
 is a 

또한 작동

$ echo "Here is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a

$ echo "Here is a StringHere is a StringHere is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a 

6

sed명령 을 이해하려면 단계별로 명령을 작성해야합니다.

원본은 여기 있습니다

user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$ 

ubstition 옵션으로 Here문자열 을 제거해 봅시다 s.sed

user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$ 

이 시점에서, 나는 당신이 제거 할 수있을 것이라고 생각 String뿐만 아니라

user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$ 

그러나 이것은 원하는 출력이 아닙니다.

두 개의 sed 명령을 결합하려면 -eoption을 사용하십시오.

user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$ 

도움이 되었기를 바랍니다


4

사용할 수 있습니다 \1( http://www.grymoire.com/Unix/Sed.html#uh-4 참조 ).

echo "Hello is a String" | sed 's/Hello\(.*\)String/\1/g'

괄호 안에있는 내용은로 저장됩니다 \1.


이것은 사이에 무언가를 출력하는 대신 문자열을 제거합니다. sed 명령에서 "is"를 사용하여 "Hello"를 제거하면 "Hello a"가 출력됩니다.
Jonathan

1

문제. 저장된 클로 메일 메시지가 다음과 같이 줄 바꿈되어 제목 줄을 추출하려고합니다.

Subject: [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular
 link in major cell growth pathway: Findings point to new potential
 therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is
 Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as
 a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway
 identified [Lysosomal amino acid transporter SLC38A9 signals arginine
 sufficiency to mTORC1]]
Message-ID: <20171019190902.18741771@VictoriasJourney.com>

이 스레드의 A2에 따라 sed / grep을 사용하여 두 단어 사이의 텍스트를 추출하는 방법은 무엇입니까? 일치하는 텍스트에 줄 바꿈이 포함되어 있지 않으면 아래의 첫 번째 표현식은 "작동"합니다.

grep -o -P '(?<=Subject: ).*(?=molecular)' corpus/01

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key

그러나 수많은 변형 ( .+?; /s; ...)을 시도했지만 작동시키지 못했습니다.

grep -o -P '(?<=Subject: ).*(?=link)' corpus/01
grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01
etc.

해결책 1.

다른 줄에서 두 문자열 사이의 추출 텍스트

sed -n '/Subject: /{:a;N;/Message-ID:/!ba; s/\n/ /g; s/\s\s*/ /g; s/.*Subject: \|Message-ID:.*//g;p}' corpus/01

어느 것이

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]                              

해결책 2. *

Per sed를 사용하여 줄 바꿈 (\ n)을 바꾸려면 어떻게해야합니까?

sed ':a;N;$!ba;s/\n/ /g' corpus/01

줄 바꿈을 공백으로 바꿉니다.

sed / grep를 사용하여 두 단어 사이의 텍스트를 추출하는 방법의 A2와 연결 ? 우리는 다음을 얻습니다.

sed ':a;N;$!ba;s/\n/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

어느 것이

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular  link in major cell growth pathway: Findings point to new potential  therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is  Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as  a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway  identified [Lysosomal amino acid transporter SLC38A9 signals arginine  sufficiency to mTORC1]] 

이 변형은 이중 공백을 제거합니다.

sed ':a;N;$!ba;s/\n/ /g; s/\s\s*/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

기부

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]

1
nice adventure :))
Alexandru-Mihai Manolescu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.