이것은 내 스크립트입니다.
#! /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에서 루프할 필요가 없습니다. 이렇게 하면 모든 내용이 변경됩니다.하나
sed
600번 실행 대신 실행됩니다 .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
,4155
및4200
변경되었습니다.3500
하지만4255
아닙니다. 필요한 것 이상입니다.[0-9]
예상대로 작동하지 않습니다일부로케일(범위에 다른 문자가 있음) 구체적으로 어떤 로케일이 무엇인지는 모르지만[0-9]
전적으로 의존하지 않을 만큼 자주 언급되는 것을 봅니다. 이것이 영향을 미치는 경우[[:digit:]]
대신 사용[0-9]
하거나perl -p
대신 사용할 수 있습니다( 대신sed
사용할 수 있음 ). range 에도 동일하게 적용됩니다 . 대신 사용하세요.\d
[0-9]
[6-9]
[6789]
$str5
마지막으로 변수에 무엇을 넣을지 매우 주의해야 합니다 .sed
명령 에 삽입되기 때문에 sed 스크립트를 쉽게 깨뜨릴 수 있습니다(예를 들어$str5
a를 포함 하면 일치가/
깨집니다 )./$str5/
sed는 스크립트 부분이 쉘 변수에서 온다는 사실을 모르고 실행되도록 지정된 스크립트만 봅니다.또한 전체 문자열은 다음과 같습니다.sed에 의해 정규식으로 해석됨
\
- 이는 정규식 메타 문자가 그렇지.
않으면 리터럴 문자로 해석되지 않음을 의미합니다.\.
답변2
do
귀하의 시도는 원칙적으로 정확합니다. frabjous가 지적한 것처럼 이전에 세미콜론으로 목록을 닫는 것을 놓쳤습니다.
for x in {3600..4200}; do
그러나 이로 인해 파일을 "그 자리에서" 601번 편집하게 되므로 실행할 때마다 수백 개의 새 파일이 효과적으로 생성되고 삭제됩니다.
이를 방지하려면 다음을 수행하십시오.
sed
재미는 있지만 그다지 유용하지는 않은 숫자에 대한 기본적인 이해를 한 번에 가르 칩니다 .python
예 를 들어 숫자를 계산할 수 있는 도구를 사용perl
하거나awk
- 그러면 입력할 수 있는 실용적인 대안이 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/