bash를 사용하여 파일의 각 줄에서 문자열을 찾아 같은 줄의 다른 문자열로 바꿉니다.

bash를 사용하여 파일의 각 줄에서 문자열을 찾아 같은 줄의 다른 문자열로 바꿉니다.

이것은 내 스크립트입니다.

#! /bin/bash

# C-band Edit
dqt='"'
str5="polarization=${dqt}2${dqt}"
for x in {3600..4200} do;
    sed -i "/$str5.*$x/s/$x/$((x-600))/" satellites.xml
done

내가 원하는 것은 str5가 포함된 Satellites.xml의 모든 줄에서 3600과 4200 사이의 숫자 x를 x-600으로 바꾸는 것입니다. 하지만 위 스크립트에서 구문 오류가 발생합니다.

답변1

x-600방금 당신이 리터럴 문자열을 의미하는 것이 아니라 "3600과 4200 사이에 있는 모든 값에서 600을 뺀다"는 뜻이라는 생각이 들었습니다 . 이 경우 sed가 아닌 Perl을 사용하십시오.

echo "$str5. foo bar 3200 3964 4155 4200 4255" |
  perl -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}"
polarization="2". foo bar 3200 3364 3555 3600 4255

이것은 Perl의 /e정규식 수정자를 사용하여 오른쪽 ( $&-600)을 다음과 같이 만듭니다.Perl 표현식으로 평가됩니다.. $&은 일치하는 값을 포함하는 Perl 변수이므로 $&-600값에서 600을 빼는 것을 의미합니다.

이것이 정말로 원하는 것이라면 아래에 원래 답변을 남겨 두겠습니다. 또한 위의 Perl 답변과 여전히 어느 정도 관련이 있는 유용한 설명이 있기 때문입니다.

sed와 마찬가지로 Perl에는 -i내부 편집 옵션이 있으므로 이를 Satellites.xml 파일에 직접 적용할 수 있습니다. man perlrun자세히보다.

perl -i -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}" satellites.xml

또한 주목할 만한 점은 XML 파일로 작업할 때 아마도 XML 파서를 사용해야 한다는 것입니다. 다행스럽게도 Perl에는 다음과 같은 몇 가지 옵션이 있습니다.XML::파서또는 컬렉션libxml-perl.


실제 입력 샘플이 없으므로 변경되는 사항과 변경되지 않는 사항을 보여주는 예를 만들었습니다.

str5='polarization="2"'

echo "$str5. foo bar 3500 3964 4155 4200 4255" | 
  sed -e "/$str5/ {s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]/4-600/g; s/4200/4-600/g}"
polarization="2". foo bar 3500 3-600 4-600 4-600 4255

영어로 대략 번역하면 "현재 줄에 $str5( )가 포함되어 있으면 polarization="2"이 세 가지 작업을 해당 줄에 적용하세요"입니다.s///

노트:

  • 3600..4200에서 루프할 필요가 없습니다. 이렇게 하면 모든 내용이 변경됩니다.하나sed600번 실행 대신 실행됩니다 .

  • 3600-4200 사이의 값을 변경하고 싶습니다. 즉, 3가지 검색 및 바꾸기 작업이 필요합니다.

    • 원피스 3600-3999
    • 4000-4199 원피스
    • 한 세트에 4200원이에요
  • 또는 s///마지막 두 작업을 하나로 결합하여 두 작업으로 수행할 수 있습니다.

      sed -e "/$str5/ { s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]\|4200/4-600/g }"
    
  • 정규식을 최적화하는 다른 방법도 많이 있을 수 있지만 더 많이 수행할수록 나중에 읽고 수정하기가 더 어려워집니다.

  • 3964, 41554200변경되었습니다. 3500하지만 4255아닙니다. 필요한 것 이상입니다.

  • [0-9]예상대로 작동하지 않습니다일부로케일(범위에 다른 문자가 있음) 구체적으로 어떤 로케일이 무엇인지는 모르지만 [0-9]전적으로 의존하지 않을 만큼 자주 언급되는 것을 봅니다. 이것이 영향을 미치는 경우 [[:digit:]]대신 사용 [0-9]하거나 perl -p대신 사용할 수 있습니다( 대신 sed사용할 수 있음 ). range 에도 동일하게 적용됩니다 . 대신 사용하세요.\d[0-9][6-9][6789]

  • $str5마지막으로 변수에 무엇을 넣을지 매우 주의해야 합니다 . sed명령 에 삽입되기 때문에 sed 스크립트를 쉽게 깨뜨릴 수 있습니다(예를 들어 $str5a를 포함 하면 일치가 /깨집니다 ). /$str5/sed는 스크립트 부분이 쉘 변수에서 온다는 사실을 모르고 실행되도록 지정된 스크립트만 봅니다.

    또한 전체 문자열은 다음과 같습니다.sed에 의해 정규식으로 해석됨\- 이는 정규식 메타 문자가 그렇지 .않으면 리터럴 문자로 해석되지 않음을 의미합니다.\.

답변2

do귀하의 시도는 원칙적으로 정확합니다. frabjous가 지적한 것처럼 이전에 세미콜론으로 목록을 닫는 것을 놓쳤습니다.

for x in {3600..4200}; do

그러나 이로 인해 파일을 "그 자리에서" 601번 편집하게 되므로 실행할 때마다 수백 개의 새 파일이 효과적으로 생성되고 삭제됩니다.

이를 방지하려면 다음을 수행하십시오.

  1. sed재미는 있지만 그다지 유용하지는 않은 숫자에 대한 기본적인 이해를 한 번에 가르 칩니다 .
  2. python예 를 들어 숫자를 계산할 수 있는 도구를 사용 perl하거나awk
  3. 그러면 입력할 수 있는 실용적인 대안이 7개로 줄어듭니다 sed.
    #! /bin/bash
    # C-band Edit
    dqt='"'
    str5="polarization=${dqt}2${dqt}"
    sed -Ei "/$str5$x/{"$(for x in {36..41}; do echo -n "s/$x([0-9]{2})/$((x-6))\\1/;"; done)";s/4200/3600/;}" satellites.xml

sed교체 시 스크립트가 생성됩니다 .

s/36([0-9]{2})/30\1/;s/37([0-9]{2})/31\1/;s/38([0-9]{2})/32\1/;s/39([0-9]{2})/33\1/;s/40([0-9]{2})/34\1/;s/41([0-9]{2})/35\1/;s/4200/3600/

관련 정보