sed는 해당 줄의 첫 번째 패턴 일치만 인쇄합니다.

sed는 해당 줄의 첫 번째 패턴 일치만 인쇄합니다.

나는 다음과 같은 데이터를 가지고 있습니다.

<td><a href="data1">abc</a> ... <a href="data2">abc</a> ... <a href="data3">abc</a>

data(위 라인은 아래 코드 와 같이 참조됩니다 )

data1첫 번째 사이에 필요하므로 "이렇게 "합니다.

echo 'data' | sed 's/.*"\(.*\)".*/\1/'

하지만 그것은 나에게 반환마지막 문자열사이 "와 항상 즉, 이 경우 대신 "나를 반환합니다.data3data1

을 얻기 위해 data1나는 결국

echo 'data' | sed 's/.*"\(.*\)".*".*".*".*".*/\1/'

data1그렇게 많은 중복 없이 이것을 어떻게 얻을 수 있습니까?sed

답변1

정규식 .*패턴은 탐욕적이며 가능한 가장 긴 문자열과 일치하므로 일치하는 인용문이 마지막 인용문이 됩니다.

여기서 구분 기호는 단 하나의 문자이므로 역괄호 세트를 사용하여 따옴표(예: )를 제외한 모든 항목과 일치시킨 [^"]다음 해당 일치를 반복하여 따옴표가 아닌 여러 문자와 일치시킬 수 있습니다.

$ echo '... "foo" ... "bar" ...' | sed 's/[^"]*"\([^"]*\)".*/\1/'
foo

또 다른 방법은 첫 번째 참조 이전의 모든 항목을 삭제한 다음 (새로운) 첫 번째 참조부터 시작하는 모든 항목을 삭제하는 것입니다.

$ echo '... "foo" ... "bar" ...' | sed 's/^[^"]*"//; s/".*$//'
foo

Perl 정규식에서는 물음표를 추가하여 지정자를 탐욕스럽지 않게 만들 수 있으며 *가능한 한 적은 문자/바이트만 제외하면 무엇이든 가능합니다.+.*?

답변2

HTML을 구문 분석하기 위해 간단한 정규식을 사용하는 것에 대한 고전적인 경고로 여러분을 지루하게 하지 않겠습니다. 내가 말하고자 하는 것은 전용 파서를 사용해야 한다는 것입니다. 즉, 여기서 문제는 sed탐욕스러운 일치를 사용하는 것입니다. 따라서 항상 가장 긴 문자열과 일치합니다. 이는 당신이 .*영원히 지속되고 전체 라인과 일치한다는 것을 의미합니다.

(아래 참조)에서 이 작업을 수행 할 수 있지만 sed탐욕스럽지 않은 일치를 허용하는 도구를 사용하는 것이 더 쉽습니다.

$ perl -pe 's/.*?"(.*?)".*/$1/' file
data1

non-greedy 매칭을 지원하지 않기 때문에 sed추가적인 트릭이 필요합니다. 가장 쉬운 방법은 "따옴표 없음" 방법을 사용하는 것입니다.이카츄의 대답. 대안은 다음과 같습니다.

$ rev file | sed 's/.*"\(.*\)".*/\1/' | rev
data1

이는 원래 방법을 사용하여 파일( rev)을 되돌린 것입니다. 이제 첫 번째 항목이 마지막 항목이기 때문에 작동하고 파일을 다시 되돌립니다.

답변3

여러 가지 방법으로 입력에서 data1을 추출할 수 있습니다.

grep -oP '^[^"]*"\K[^"]*'

sed -ne '
   /\n/!{y/"/\n/;D;}
   P
'

perl -lne '/"([^"]*)"/ and print($1),last'

답변4

Perl 정규식 예측 및 예측을 사용하여 탐욕스럽지 않은 검색을 사용할 수도 있습니다.

cat data | grep -Po '(?<=href=").*?(?=")' | head -n1

관련 정보