내 Linux 컴퓨터에 다음 파일이 있습니다.
<names>
<first_name>Mohammed Sani</first_name>
<last_name>ABACHA</last_name>
<aliases>
<alias>ABACHE,Mohammed Sani</alias>
<alias>SANI,Mohammed</alias>
</aliases>
<low_quality_aliases>
<alias xsi:nil="true"/>
</low_quality_aliases>
<alternative_spelling xsi:nil="true"/>
</names>
다음 명령을 사용하여 이름을 인쇄하지만 이름만 인쇄합니다.
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p' 'test.xml' > name.txt
성을 추가하려면 어떻게 해야 하나요?
답변1
이름과 성 데이터가 같은 줄에 있고 그 사이에 탭이 있기를 원한다고 가정해 보겠습니다.
사용 xmlstarlet
:
xmlstarlet sel -t -m '/names' \
-v 'first_name' -nl \
-v 'last_name' -nl file.xml 2>/dev/null |
paste - -
이 명령은 해당 노드와 그 아래 노드의 값을 파싱하여 xmlstarlet
각각 한 줄씩 출력합니다.first_name
last_name
names
탭 문자를 구분 기호로 사용하여 출력의 두 줄을 한 줄에 붙여넣는 데 사용됩니다 paste
. 예를 들어 with를 사용 -d ','
하면 paste
쉼표로 구분된 출력을 얻을 수 있습니다.
/dev/null
나중에 문서에 xmlstarlet
올바른 일부 가짜 네임스페이스 선언이 있기 때문에 표준 오류 스트림을 로 리디렉션합니다 .
xq
다음에서 사용https://kislyuk.github.io/yq/:
xq -r '.names | [ .first_name, .last_name ] | @tsv' file.xml
이는 @tsv
연산자를 사용하여 탭으로 구분된 출력을 생성합니다. 위의 코드와 동일한 데이터를 출력 xmlstarlet
하지만 XPath 표현식 대신 표현식을 사용합니다 jq
.
대신 전체 인용된 CSV 출력을 @tsv
얻으세요 .@csv
답변2
두 번째 명령을 추가할 수 있습니다 s
.
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p;s:.*<last_name>\(.*\)</last_name>.*:\1:p' 'test.xml' > name.txt
또는 확장 정규식을 사용하세요.
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' 'test.xml' > name.txt
업데이트: 두 이름을 같은 줄에 출력하도록 요청
동일한 줄에 출력을 넣으려면 다른 스크립트를 통해 공백이 있는 줄로 파이프하면 됩니다.
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' test.xml | sed 'H;1h;$!d;g;s/\n/ /g' > name.txt
패턴 공간의 모든 라인을 연결하는 데 사용됩니다 H,1h;$1d;g
( H
모든 라인을 예약된 공간에 추가하고, 1h
이전 줄바꿈을 방지하기 위해 첫 번째 라인의 예약된 공간을 덮어쓰고, $!d
마지막 라인을 제외한 모든 라인 처리를 중지하고, g
예약된 공간 내용을 패턴 공간으로 이동). 그런 다음 s/\n/ /g
모든 줄 바꿈을 공백으로 바꾸십시오. 귀하의 경우에는 g
항상 두 줄만 있을 것이라고 확신한다면 이를 제거할 수 있습니다.
Linux에서는 GNU가 있고 동일한 결과를 sed
얻을 수 있습니다.sed -z 's/\n/ /g'
보다 우아하게, 파일에서 여러 이름 쌍을 처리할 수 있으면 다음과 같은 작업도 수행할 수 있습니다.
sed -e '/.*<first_name>\(.*\)<\/first_name>.*/{s//\1/;h;}' -e '/.*<last_name>\(.*\)<\/last_name>.*/!d;s//\1/;H;g;s/\n/ /' 'test.xml' > name.txt