저는 몇 주 전에 업데이트된 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;$!ba
GNU에서만 작동합니다 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
에 사용되지 않는 임의의 문자열입니다 .key
keybind
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
해당 위치에서 편집이 수행되어 원본 파일이 수정됩니다.