파일에서 줄을 찾아 태그에 포함된 데이터 정리

파일에서 줄을 찾아 태그에 포함된 데이터 정리

아래와 같은 파일을 정리(제자리에서 편집)하려고 합니다.

<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>

<id>474490</id>
<name>Bob</name>
<nr>.27. 43-88</nr> # this is the line of interest

<id>474568</id>
<name>Jim</name>
<nr>
</nr> # sometimes there will be no value and a closing tag on a newline, this can be ignored
....

원하는 출력:

<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>

<id>474490</id>
<name>Bob</name>
<nr>274388</nr> # note that nr data has been cleaned to digits only

<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....

즉, <nr> </nr>라벨에 포함된 데이터에서 숫자가 아닌 문자를 모두 제거하거나 특정 문자를 제거하고 싶습니다.

내 코드:

sed -Ee  '/<nr>/ s/>(.*)</>\1</g' test1.txt

이것이 하는 일:

  • <nr>다음에 포함된 행만 선택하세요 .

  • 그 안의 레이블과 콘텐츠를 교체합니다(그룹 1의 콘텐츠 캡처 = 그룹 1의 콘텐츠 캡처로 무엇을 해야 할지 모르기 때문에 변경 사항 없음).

또한 이상적으로는 을 교체하고 싶지 않지만 sed에서 sed 이후 및 이전에 > <시작하도록 지시하는 것은 sed에서는 불가능해 보입니다.><

무엇을 추가해야 합니까(그러나 방법을 모르겠습니다):

삽입하기 전에 캡처 그룹 1의 내용을 필터링합니다(제거 .- /또는 숫자만 허용).whitespace

어떻게 해야 하나요?

다른 도구를 사용해야 합니까?

답변1

이는 XML 조각처럼 보입니다. <root/>다음 XML을 갖도록 닫는 요소를 추가한 다음 XML 편집 도구를 사용할 수 있습니다.

xmlstarlet ed -u '//nr' -x 'translate(text(), "- .", "")' file.xml
<?xml version="1.0"?>
<root>
  <id>474488</id>
  <name>Shawn</name>
  <nr>143385</nr>
  <id>474490</id>
  <name>Bob</name>
  <nr>274388</nr>
  <id>474568</id>
  <name>Jim</name>
  <nr>
</nr>
</root>

여기서 중요한 부분은 XPath translate()기능입니다. 한 문자열의 문자를 다른 문자열의 문자로 바꾼다는 점에서 UNIX/Linux 명령과 유사하게 작동합니다 tr(첫 번째 매개변수는 연산할 값입니다).

나는 그것을 nr작업을 위한 후크로 사용합니다. 필요한 경우 요소 경로가 더 정확해질 수 있습니다( 제 예에서도 /root/nr작동합니다 ).

실제로 파일을 처리하는 필터링 도구는 거의 없습니다. 임시 파일을 작성한 다음 이를 사용하여 원본 파일을 대체합니다. 이 경우에는 직접 구현해야 합니다.

xmlstarlet ... file.xml >file.xml.tmp && mv -f file.xml.tmp file.xml

답변2

이것이 XML과 같이 적절하게 구조화된 언어라면 실제로 전용 파서를 사용해야 합니다(예 xmlstarlet: 이를 고려하십시오). 즉, 파일이 메모리에 들어갈 만큼 작으면 주석에서 언급한 대로 필드가 비어 있는 경우에만 줄 바꿈이 있으므로 교체가 필요하지 않다고 가정하면 실제로 다음을 수행할 수 있습니다. 방법:

$ sed '/<nr>/{s/[. -]*//g}' file
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>

<id>474490</id>
<name>Bob</name>
<nr>274388</nr>#thisisthelineofinterest

<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....

더 복잡한 경우에 적절한 파서를 사용할 수 없으면 Perl을 사용합니다.

$ perl -nle '$k=1 if /<nr>/; if($k){s/[. -]//g}; $k=0 if /<\/nr>/; print' file
<id>474488</id>
<name>Shawn</name>
<nr>143385</nr>

<id>474490</id>
<name>Bob</name>
<nr>274388</nr>#thisisthelineofinterest

<id>474568</id>
<name>Jim</name>
<nr>
</nr>
....

그러나 다음과 같이 같은 줄에 여러 레이블이 있을 수 있는 경우 위의 작업은 실패합니다.

<nr>143385</nr><name>Shawn - Mary</name>

이 경우 -의 값에서도 제거됩니다 <name>. 이 극단적인 경우는 파서가 실제로 최선의 선택인 이유입니다.

perl및 옵션 의 경우 파일의 내부 편집을 sed사용할 수 있습니다 .-i

sed -i '/<nr>/{s/[. -]*//g}' file
perl -i -nle '$k=1 if /<nr>/; if($k){s/[. -]//g}; $k=0 if /<\/nr>/; print' file

관련 정보