텍스트 파일(XML)에서 개행 문자가 포함된 문자열을 교환하기 위한 스크립트

텍스트 파일(XML)에서 개행 문자가 포함된 문자열을 교환하기 위한 스크립트

저는 몇 주 전에 업데이트된 Arch를 사용하고 있습니다. 사용된 패키지는

  • 아치 6.0.10-arch2-1
  • BASH 5.1.16(1)-출시
  • 그누스 4.9
  • 그누 grep 3.8
  • 3.6.1 언박싱

내 Openbox rc.xml텍스트 파일에는 다음과 같은 두 줄이 있습니다.

<!-- <keybind key="Right"> -->

<keybind key="s-Up">

스크립트를 사용하여 위의 두 줄과 아래의 두 줄을 자주 전환/교환하고 싶습니다.

<!-- <keybind key="s-Up"> -->

<keybind key="Right">

rc.xml이를 통해 매번 키 바인딩 설정 텍스트 파일( )을 지루하게 편집할 필요 없이 빠르게 키 바인딩을 변경할 수 있습니다.

지금까지 내 스크립트는 다음과 같지만 가깝다는 것을 알고 있지만 작동하지 않습니다.

나는 이 스위치를 어떻게 구현하는지 별로 관심이 없지만 이것에 많은 시간을 투자했기 때문에 아래 스크립트가 작동하도록 하는 것이 좋을 것입니다.

아래 표현식은 sed텍스트 교환 작업을 정상적으로 수행합니다.

문은 조건이 충족되면 if첫 번째 스왑을 수행 하지만 sed조건이 충족되지 않으면 두 번째 스왑을 수행하지 않는 것으로 보이는 것이 문제입니다.sed

var_a=""

#var_a=$(grep -zoP  "<\!\-\- <keybind key=\"Right\"> \-\->\n\n<keybind key=\"s-Up\">" /home/kes/Dropbox/lubuntu-rc.xml | sed ':a;N;$!ba;s|\n\n||g')

var_a=$(grep -zoP  "<\!\-\- <keybind key=\"Right\"> \-\->\n\n<keybind key=\"s-Up\">" /home/kes/Dropbox/lubuntu-rc.xml | tr -d '\n' )

# result of grep is
# <!-- <keybind key="Right"> --><keybind key="s-Up">

echo $var_a; sleep 0.5

#if [[ -z ! "$var_a" ];then
if [[ '$var_a'=='<!-- <keybind key="Right"> --><keybind key="s-Up">' ]]; then

   sed -ie ':a;N;$!ba;s|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|g' /home/kes/Dropbox/lubuntu-rc.xml

else

   sed -ie ':a;N;$!ba;s|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|g' /home/kes/Dropbox/lubuntu-rc.xml

fi

답변1

실제로 작은 따옴표로 인해 '$var_a'변수가 확장되지 않으므로 이 조건은 결코 충족되지 않습니다. 따라서 리터럴 문자열은 $var_a다른 리터럴 문자열과 결코 동일하지 않습니다.

큰따옴표를 사용하면 작동합니다.하지만귀하의 스크립트에 몇 가지 설명을 추가하고 싶습니다.

(1)먼저 수행한 grep다음 이를 통해 얻은 결과를 기반으로 조건을 구축하고 grep마지막으로 두 가지 다른 sed스크립트를 사용합니다. 이로 인해 오류가 발생할 수 있습니다. 실제로 sed모든 작업을 혼자서 수행하게 됩니다.

sed -ie ':a;N;$!ba
  s|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|g
  t
  s|<!-- <keybind key="s-Up"> -->\n\n<keybind key="Right">|<!-- <keybind key="Right"> -->\n\n<keybind key="s-Up">|g' \
  /home/kes/Dropbox/lubuntu-rc.xml

첫 번째 대체가 이루어진 경우 t스크립트 끝으로 점프하고, 그렇지 않으면 다른 대체를 수행하십시오. 이미 포함되어 grep있습니다 if!

(2)모든 행을 수집하는 방법은 :a;N;$!baGNU에서만 작동합니다 sed. POSIX 표준에 따르면 콜론 뒤의 모든 항목은 점프 표시가 되며 예외는 아니기 때문입니다 ;. GNU가 있으므로 문제가 되지 않습니다 . 그러나 부품 없이 한 번에 구멍 파일을 처리하도록 선택할 sed수도 있습니다 . -z휴대성을 선호한다면 H;1h;$!d;x저장 공간도 똑같이 할 수 있습니다.

(삼)제 생각에는 g이 줄이 한 번만 존재하기 때문에 전역 플래그가 중복되는 것 같습니다. 그렇죠?

(4)같은 내용을 반복해서 쓰면 오류가 발생하고 읽기가 더 어려워질 수 있습니다. 부품에 태그를 지정 \(\)하고 로 참조하여 부품을 재사용하는 것은 어떨까요 \1?

sed -iz 's|<!-- \(<keybind key="\)Right"> -->\n\n\1s-Up">|<!-- \1s-Up"> -->\n\n\1Right">|
  t
  s|<!-- \(<keybind key="\)s-Up"> -->\n\n\1Right">|<!-- \1Right"> -->\n\n\1s-Up">|' \
  /home/kes/Dropbox/lubuntu-rc.xml

(5)실제로 전체 파일을 하나로 처리할 필요는 없습니다(큰 파일도 오버플로될 수 있음). 이 N;P;D구성표를 사용하여 세 줄의 연속 라인을 모두 함께 처리하면 됩니다(보통 두 줄을 함께 처리하고 1N확장하려면 추가하세요). 3개 OK):

sed -i '1N;N
  s|<!-- \(<keybind key="\)Right"> -->\n\n\1s-Up">|<!-- \1s-Up"> -->\n\n\1Right">|
  t
  s|<!-- \(<keybind key="\)s-Up"> -->\n\n\1Right">|<!-- \1Right"> -->\n\n\1s-Up">|;
  P;D' /home/kes/Dropbox/lubuntu-rc.xml

이를 더 단순화할 수도 있지만 파일 내용에 대한 추가 정보가 필요합니다.

답변2

XML 문서의 형식이 올바르고 구문이 정확하다고 가정하면 XML 프로세서를 사용하여 xmlstarlet값을 전환할 수 있습니다.

문서에서 주석 처리된 XML을 무시하고, 다음은 먼저 key각 노드의 모든 속성을 keybind값에서 (다른 값을 가진 속성은 영향을 받지 않음) Right로 변경하여 이를 수행합니다. 그런 다음 temporary동일한 속성을 에서 로 s-Up변경 Right하고 마지막으로 에서 로 temporary변경 합니다 s-Up. 이 문자열은 노드 의 속성 temporary에 사용되지 않는 임의의 문자열입니다 .keykeybind

Right이는 값을 효과적으로 바꾸거나 s-Up그 반대로 바꿉니다.

xmlstarlet edit \
    --var attr '//keybind/@key' \
    --update '$attr[.="Right"]'     --value temporary \
    --update '$attr[.="s-Up"]'      --value Right \
    --update '$attr[.="temporary"]' --value s-Up \
   file.xml

그러면 문서가 다음과 같이 바뀔 것입니다.

<?xml version="1.0"?>
<root>
  <keybind key="s-Up"/>
  <keybind key="s-Down"/>
  <keybind key="Right"/>
</root>

... 입력하다

<?xml version="1.0"?>
<root>
  <keybind key="Right"/>
  <keybind key="s-Down"/>
  <keybind key="s-Up"/>
</root>

--inplace명령줄에서 단어 바로 뒤에 삽입 하면 edit해당 위치에서 편집이 수행되어 원본 파일이 수정됩니다.

관련 정보