grep
두 문자열이 같은 줄에 나타나지 않는 경우 블록 내에서 AND 조건을 사용하여 두 문자열을 나타내는 방법을 알고 싶습니다. 다음을 시도했지만 같은 줄에 있지 않은 문자열에서는 작동하지 않습니다.
grep 'string1.*string2\|string2.*string1' filename
grep -P '^(?=.*pattern1)(?=.*pattern2)' filename
예를 들어 다음 줄을 포함하는 xml 파일이 있습니다.
<test-result
exectime="2017-07-07"
result="FAILURE"
isdone="TRUE"
logicalname="this.is.test1"
duration="10050"
>
<test-case
testcasename="this.is.test.case.name1"
testunit="abcd-mc"
testpath="file:/this/is/the/file/path1/abcd.xml"
>
</test-case>
</test-result>
<test-result
exectime="2017-07-07"
result="SUCCESS"
isdone="TRUE"
logicalname="this.is.test1"
duration="10050"
>
<test-case
testcasename="this.is.test.case.name1"
testunit="abcd-mc"
testpath="file:/this/is/the/file/path1/uvwx.xml"
>
</test-case>
</test-result>
태그 안에는 2개의 코드 블록이 <test-result></test-result>
있으므로 동일한 블록에 해당하는 값을 AND ( AND ) 로 찾고 testpath
싶습니다 .grep
logicalname
result
grep
this.is.test1
FAILURE
testpath
testpath
다음으로, 장면의 가 있으면 결과가 " 내가 찾았습니다" 및 ? 에 FAILURE
맞도록 파일을 어떻게 수정합니까 ?SUCCESS
testpath
logicalname
답변1
내 제안은“그럴려고 애쓰지도 마세요 grep
”. awk
또는 에서 일부 이상한 정규식 기반 해킹을 제거 할 수 있지만 perl
정규식은 그렇지 않습니다.안정적으로XML에서 데이터를 구문 분석하거나 추출하는 데 사용됩니다. 무엇을 생각해내든 읽을 수 없고 유지 관리도 불가능한 엉망이 될 가능성이 높습니다. 더 좋은 방법이 있습니다. 실용적이고 효과적이며 신뢰할 수 있는 방법입니다.
즉, XML이나 HTML을 구문 분석하지 마세요.정규 표현식 사용. 그것작동하지 않습니다.
대신 다음과 같은 XML 파서를 사용하세요.xmlstarlet. 또는 선택할 수 있는 여러 XML 구문 분석 라이브러리가 있는 perl
또는 같은 언어를 사용하세요.python
grep
줄 기반 도구 (또는 더 나은 방법 awk
, perl
심지어 ) 를 사용하여 XML을 처리하려면 sed
먼저 다음을 사용하여 xml을 줄 기반 형식으로 변환하세요.XML2. 이는 XML 파일에서 매우 간단한 데이터 추출에 적합한 선택입니다.
예를 들어, 샘플 XML에서 가장 명백한 오류를 수정한 후의 모습은 다음과 같습니다 xml2
.
$ xml2 < ajs.xml
/xml/test-result/@exectime=2017-07-07
/xml/test-result/@result=FAILURE
/xml/test-result/@isdone=TRUE
/xml/test-result/@logicalname=this.is.test1
/xml/test-result/@duration=10050
/xml/test-result/test-case/@testcasename=this.is.test.case.name1
/xml/test-result/test-case/@testunit=abcd-mc
/xml/test-result/test-case/@testpath=file:/this/is/the/file/path1/abcd.xml
/xml/test-result
/xml/test-result/@exectime=2017-07-07
/xml/test-result/@result=SUCCESS
/xml/test-result/@isdone=TRUE
/xml/test-result/@logicalname=this.is.test1
/xml/test-result/@duration=10050
/xml/test-result/test-case/@testcasename=this.is.test.case.name1
/xml/test-result/test-case/@testunit=abcd-mc
/xml/test-result/test-case/@testpath=file:/this/is/the/file/path1/uvwx.xml
단지 그것을 사용하여 원하는 것을 얻는 것은 어렵지만 아마도 사용하기 매우 쉬울 grep
것이고 perl
(XML 라이브러리를 사용하지 않고 그냥 평범한 Perl) awk
사용하기에도 그리 어렵지 않습니다 sed
.
또는 에서 XML 구문 분석 라이브러리를 사용하는 것이 xmlstarlet
더 쉽습니다 . 이러한 모든 방법은 XML 문서의 구조화된 데이터와 직접 작동합니다. 즉, 각 XML 요소는 어떤 방식으로든 연결될 수 있는 행 묶음이 아니라 선택적 속성과 값이 있는 고유한 개체로 처리됩니다.perl
python
그런데 좋은 답변이 있는 질문이 많아요xmlstarlet그리고XML2이 웹사이트에서.
xml2
둘 다 xmlstarlet
대부분의 Linux 배포판에 사전 패키지되어 있습니다.
마지막으로 최소한 잘 구조화된 XML로 시작해보세요. 위의 샘플 XML에는 몇 가지 결함이 있습니다. 손상되었거나 불완전하거나 비표준 XML 입력을 구문 분석하는 도구는 어렵습니다.
답변2
"XML 구문 분석은 나쁜 습관입니다"라고 언급하면서 awk
문제에 대한 해결책은 다음과 같습니다. :)
awk -v RS="<test-result" '
/logicalname="this\.is\.test1"/&&/result="FAILURE"/ {
sub("FAILURE","SUCCESS")
}1' RS='' infile.txt
위에서 우리는 awk
말한다오른쪽에코코드에스연산자 는 다음과 RS
같습니다 <test-result
. 각 레코드에 대해 두 개의 패턴( logicalname="this.is.test1"
및 result="FAILURE"
)이 검색되고 해당 패턴이 있으면(동일 블록 내에서) FAILURE
지정된 SUCCESS
패턴이 다음으로 변경됩니다 .infile.txt
주석에서 말했듯이 특정 블록 변경을 사용하고 싶기 때문에 testpath=....
명령에 또 다른 세 번째 조건을 추가하면 됩니다. 다음 내용도 표시되는 경우에만 변경됩니다 testpath="file:/this/is/the/file/path1/abcd.xml"
.
escape 가 필요하며 /
, 가급적 escape .
s도 수행해야 합니다.
awk -v RS="<test-result" ' /logicalname="this\.is\.test1"/&&/result="FAILURE"/&&/testpath="file:\/this\/is\/the\/file\/path1\/abcd\.xml"/
{sub("FAILURE","SUCCESS")
}1' RS='' infile.txt