다음 내용의 파일이 있습니다.
<username><![CDATA[name]]></username>
<password><![CDATA[password]]></password>
<dbname><![CDATA[name]]></dbname>
첫 번째 줄의 “name”을 “something”으로 바꾸고 두 번째 줄의 “password”를 “somethingelse”로 바꾸고 세 번째 줄의 “name”을 “somethingdifferent”로 바꾸는 스크립트를 만들어야합니다. 파일에서 발생하는 순서에 의존 할 수 없으므로 “name”의 첫 번째 항목을 “something”으로 바꾸고 “name”의 두 번째 항목을 “somethingdifferent”로 간단히 바꿀 수 없습니다. 실제로 올바른 문자열을 찾아 바꾸려면 주변 문자열을 검색해야합니다.
지금까지 첫 번째 “이름”어커런스를 찾아서 바꾸기 위해이 명령을 시도했습니다.
sed -i "s/<username><![CDATA[name]]><\/username>/something/g" file.xml
그러나 그것은 작동하지 않으므로이 문자 중 일부는 탈출해야 할 수도 있습니다.
이상적으로는 정규식을 사용하여 두 “사용자 이름”어커런스를 일치시키고 “이름”만 바꿀 수 있기를 바랍니다. 이 같은하지만 sed
:
<username>.+?(name).+?</username>
괄호 안의 내용을 “무언가”로 바꿉니다.
이게 가능해?
답변
sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml
이것은 당신이 찾고있는 것입니다.
설명:
- 첫 번째 부분의 괄호는 두 번째 부분에서 재사용 할 수있는 그룹 (사실 문자열)을 정의합니다.
\1
,\2
등 번째 부분의 첫 번째 부분에서 캡처 i 번째 그룹에 대한 참조는 (번호 매기기는 1로 시작)-E
확장 정규식 (필요+
하고 그룹화) 을 활성화 합니다.
답변
sed -e '/username/s/CDATA\[name\]/CDATA\[something\]/' \
-e '/password/s/CDATA\[password\]/CDATA\[somethingelse\]/' \
-e '/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/' file.txt
/username/
는 전에 s
문자열 ‘이름’을 포함하는 라인에만 작업에 나오지도 알려줍니다.
답변
sed
어려운 요구 사항이 아닌 경우 전용 도구를 사용하는 것이 좋습니다.
파일이 유효한 XML (3 개의 XML 모양 태그가 아닌) 인 경우 XMLStarlet 을 사용할 수 있습니다 .
xml ed -P -O -L \
-u '//username/text()' -v 'something' \
-u '//password/text()' -v 'somethingelse' \
-u '//dbname/text()' -v 'somethingdifferent' file.xml
위의 내용은 정규 표현식으로 해결하기 어려운 상황에서도 작동합니다.
- 현재 값을 지정하지 않고 태그 값을 바꿀 수 있습니다.
- 이스케이프되고 CDATA에 포함되지 않은 경우에도 값을 바꿀 수 있습니다.
- 태그에 속성이있는 경우에도 값을 바꿀 수 있습니다.
- 동일한 이름을 가진 태그가 여러 개있는 경우 태그를 쉽게 교체 할 수 있습니다.
- 수정 된 XML을 들여 쓰기하여 서식을 지정할 수 있습니다.
위의 간단한 데모 :
bash-4.2$ cat file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[name]]></username>
<password>password</password>
<dbname foo="bar"><![CDATA[name]]></dbname>
</apprentice>
</sith>
bash-4.2$ xml ed -O -u '//apprentice/username/text()' -v 'something' -u '//password/text()' -v 'somethingelse' -u '//dbname/text()' -v 'somethingdifferent' file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[something]]></username>
<password>somethingelse</password>
<dbname foo="bar"><![CDATA[somethingdifferent]]></dbname>
</apprentice>
</sith>
답변
명령 \[.*^$/
의 정규식 부분 s
과 \&/
대체 부분에 개행 을 인용해야합니다 . 정규식은 기본 정규식 이며 s
명령 의 구분 기호를 인용해야합니다 .
인용 부호를 사용하지 않기 위해 다른 구분 기호를 선택할 수 있습니다 /
. 대신 해당 문자를 인용해야하지만 일반적으로 구분 기호를 변경하는 요점은 대체 할 텍스트 또는 대체 텍스트에서 발생하지 않는 것을 선택하는 것입니다.
sed -e 's~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~'
그룹을 사용하여 대체 텍스트에서 일부 부분이 반복되는 것을 피하고 이러한 부분의 변형을 수용 할 수 있습니다.
sed -e 's~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~'
sed -e 's~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~'
답변
$ sed -e '1s/name/something/2' \
-e '3s/name/somethingdifferent/2' \
-e 's/password/somethingelse/2' sample.xml
행 번호를 나타내는 “s”앞의 숫자와 같이 주소를 간단히 사용할 수 있습니다.
또한 마지막 숫자 sed
는 첫 번째 일치 항목을 바꾸는 대신 두 번째 일치 항목을 바꾸 라고 지시 합니다.
답변
“name”단어를 “something”단어로 바꾸려면 다음을 사용하십시오.
sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml
그것은 지정된 단어의 모든 발생을 대체 할 것입니다.
지금까지 모든 것이 표준 출력으로 출력됩니다.
sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml > anotherfile.xml
다른 파일에 변경 사항을 저장합니다.
답변
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
-r, --regexp-extended
use extended regular expressions in the script.
속성 파일의 값을 바꾸려면
sed -i -r 's/MAIL\=(.+)/MAIL\=user@mymail.com/' etc/service.properties