태그 보관물: regular-expression

regular-expression

sed를 사용하여 복잡한 문자열 찾기 및 바꾸기 (바람직하게 정규식으로) 실제로 올바른 문자열을 찾아 바꾸려면

다음 내용의 파일이 있습니다.

<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