그래서 저는 XML 파일을 구문 분석하고 해당 파일 아래에 있는 카테고리 이름을 기반으로 출력을 새 파일로 리디렉션하는 간단한 스크립트를 작성하려고 합니다. 예를 들어 XML 파일은 다음과 같습니다.
<category> Music </Category>
<url>https://www.youtube.com/watch?v=waAlgFq9Xq8</url>
<category> Movies </Category>
<url>https://www.youtube.com/watch?v=g4U4BQW9OEk</url>
내 스크립트는 다음과 같습니다
for i in *.xml; do
name=$(grep -i "<category>" $i | awk '{print $1}')
line=$(grep -i -A1 "<category>" $i)
echo "$line" >> $filename
done
예를 들어 Movies.log에는 영화 카테고리에 있는 모든 링크가 포함되고, Music.log에는 음악 카테고리에 있는 모든 링크가 포함됩니다.
답변1
각 카테고리를 반복하는 것을 고려해 보셨나요? 이와 같이:
for i in *.xml; do
for category in $(sed -rn '/^<category>/{s/[^>]*> *([^ <]*).*/\1/p}' "$i"); do
sed -rn "/^<category> *$category/,/^<category>/{s/<url> *([^ <]*).*/\1/p}" "$i" > "$category.log"
done
done
업데이트: awk 사용
awk -v 'RS=<' -v 'cat=none' -F '>' \
'$1 ~ /^category$/ {gsub(/^ *| *$/,"",$2); cat=$2} \
$1 ~ /^url$/ {print $2 >> cat".log"}' \
*.xml
이렇게 하면 입력 파일이 반복되는 것을 방지하고
.log
모든 카테고리의 파일에 추가됩니다.awk의 레코드 구분 기호 할당을 사용한다는 것은
-v 'RS=<'
카테고리/URL 태그를 어디에서나(줄의 시작 부분뿐만 아니라) 찾을 수 있음을 의미합니다. 개행 문자는 xml 데이터의 어느 곳에나 나타날 수 있습니다.이를 필드 구분 기호 설정과 결합
'>'
하면 각 레코드의 첫 번째 필드가 xml 태그 이름과 동일해집니다.awk는 첫 번째 필드가 "category"인 레코드를 만날 때마다
cat
변수를 해당 카테고리의 이름으로 설정합니다.awk는 첫 번째 필드가 "url"인 레코드를 발견하면 해당 URL을 파일에 추가합니다
cat.log
.cat
none
시작 으로 정의됩니다 . 이렇게 하면<url>
앞에 a가 없는 상황에서 오류가 발생하는 것을 방지할 수 있습니다<category>
.대체 방법은
gsub(/^ *| *$/,"",$2)
예제 입력 파일에 나타나는 범주 이름에서 선행/후행 공백을 제거하는 것입니다.xml
.
노트:
위의 어느 것도 완벽하지 않습니다. 올바른 XML 입력 파일의 경우 실제 XML 파서가 더 좋습니다.xmlstarlet. 그러나 이를 위해서는 올바른 형식의 xml 파일도 필요합니다( <category>
예를 들어, 예제 입력에는 일치하는 태그가 없습니다).
답변2
저는 다음 솔루션을 준비했습니다.
grep -hP "<category.*>|<url.*>" *.xml | cut -d ">" -f 2 | cut -d "<" -f 1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | gawk 'BEGIN { category = ""; } { if (!length($0)) { next; } if (length(category)) { printf("\necho -e \"%s\" >> \"%s.log\"", $0, category); category = ""; } else { category = $0; } } END { printf("\n"); }' | bash
현재 디렉터리의 모든 .xml 파일을 검색하고추가URL 앞 줄에 있는 카테고리 이름을 따서 명명된 파일의 URL(끝에서 | bash를 제거하여 출력을 확인할 수 있습니다).
관심 있는 데이터에 대해서만 XML 노드를 추출합니다.
예를 들어 grep을 사용하여 다음 이름의 파일에서 패턴을 검색합니다.*.xml, 파일 이름을 반복할 필요가 없습니다. 옵션-시간grep은 출력에서 파일 이름을 억제합니다. grep에 제공되는 패턴은 Perl 호환 정규식(-피)
관심 있는 노드의 값을 추출합니다.
grep 명령에 의해 반환된 줄은 다음과 같습니다.
<category> MyMusic </category>
<url>https://www.youtube.com/watch?v=waAlgFq9Xq8123</url>
<category> MyMovies </category>
<url>https://www.youtube.com/watch?v=g4U4BQW9OEk456</url>
<category>Music</category>
<url>https://www.youtube.com/watch?v=waAlg</url>
<category> Music </category>
<url>https://www.youtube.com/watch?v=waAlgFq9Xq8</url>
<category> Movies </category>
<url>https://www.youtube.com/watch?v=g4U4BQW9OEk</url>
원하지 않는 데이터 행을 필터링했습니다. 이제 노드 내의 값을 추출해야 합니다. 이는 시작 태그와 끝 태그 사이의 데이터, 즉 기호 사이의 데이터를 추출하는 것으로 요약됩니다.>그리고<(우리는 그것이 어떤 노드인지 상관하지 않으므로 "일반" 방법을 사용합니다).
이는 쉽게 달성할 수 있습니다.| cut -d ">" -f 2 | cut -d "<" -f 1
이는 본질적으로 모든 것을 기호 >(-f 2)의 오른쪽으로 가져간 다음, 우리가 얻는 새로운 결과에 따라 기호 <(-f 1)의 왼쪽으로 모든 것을 가져오는 것을 의미합니다.
이는 우리에게 다음과 같은 결과를 남깁니다.
MyMusic
https://www.youtube.com/watch?v=waAlgFq9Xq8123
MyMovies
https://www.youtube.com/watch?v=g4U4BQW9OEk456
Music
https://www.youtube.com/watch?v=waAlg
Music
https://www.youtube.com/watch?v=waAlgFq9Xq8
Movies
https://www.youtube.com/watch?v=g4U4BQW9OEk
이제 이러한 값을 정리해야 합니다. 여기에 작은 수정 단계가 있습니다.
트림 값
선행 및 후행 공백 자르기| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
그리고-이자형, sed는 추가 sed 명령(또는 다른 경우에는 여러 sed 명령)을 파이프하지 않고도 지정된 순서로 스크립트를 실행할 수 있습니다.
sed에 전달된 첫 번째 스크립트는 선행 공백(즉, 문자열 시작 부분의 모든 [:space:] 문자(한 줄당))을 자르고, 두 번째 스크립트는 후행 공백(즉, 끝 앞의 모든 [:space:])을 자릅니다. ] 문자) 문자열(@각 줄)입니다.
이제 이와 같은 것이 있으므로 거의 완료되었습니다.
MyMusic
https://www.youtube.com/watch?v=waAlgFq9Xq8123
MyMovies
https://www.youtube.com/watch?v=g4U4BQW9OEk456
Music
https://www.youtube.com/watch?v=waAlg
Music
https://www.youtube.com/watch?v=waAlgFq9Xq8
Movies
https://www.youtube.com/watch?v=g4U4BQW9OEk
표준 출력에 파일 추가 명령 쓰기
파일에 데이터를 추가하기 위해 echo 명령을 작성한 것처럼 해당 프로세스를 자동화할 수 있는 것이 필요합니다. 나는 유휴 상태를 선택합니다. gawk는 데이터를 한 줄씩 읽고 범주를 변수로 가져옵니다. 다른 행을 읽을 때 카테고리 변수가 비어 있지 않으면 행에 URL이 포함됩니다. 이 기술을 사용하면 echo -e "current url" >> current_category.log와 같은 명령을 간단히 실행할 수 있습니다.
알아채다비판적인>>를 사용하여 파일에 새 데이터를 추가합니다. >를 사용하면 마지막 URL만 작성되며 카테고리당 행이 하나씩 표시됩니다!
결과적으로 우리는 표준 출력에 다음 데이터를 썼습니다.
echo -e "https://www.youtube.com/watch?v=waAlgFq9Xq8123" >> "MyMusic.log"
echo -e "https://www.youtube.com/watch?v=g4U4BQW9OEk456" >> "MyMovies.log"
echo -e "https://www.youtube.com/watch?v=waAlg" >> "Music.log"
echo -e "https://www.youtube.com/watch?v=waAlgFq9Xq8" >> "Music.log"
echo -e "https://www.youtube.com/watch?v=g4U4BQW9OEk" >> "Movies.log"
bash 실행에 데이터 추가 명령 전달
파이프라인의 마지막 요소는 | bash
echo 명령이 실행을 위해 bash에 전달되도록 합니다.
gawk는 파일에 데이터를 쓰거나 추가할 수 있습니다. 그러나 나는 의도적으로 가능한 가장 작은 gawk 스크립트를 갖고 싶었습니다.