를 사용하는 방법 sed to replace 만 첫 번째 파일에 있는?
-
02-07-2019 - |
문제
하고 싶의 큰 숫자를 업데이트 C++소스 파일에 추가 포함한 지시기 전에 모든 기존#포함되어 있습니다.이 종류의 작업,나는 일반적으로 사용하는 작은 bash 스크립트와 함께 나오지를 다시 작성하는 파일입니다.
나는 어떻게 얻 sed
대체하는 첫 번째의 발생에서 문자열이 아닌 파일 교체하는 모든 발생?
내가 사용하는 경우
sed s/#include/#include "newfile.h"\n#include/
그것을 대체하는 모든#포함되어 있습니다.
대체 제안이 같은 일을 달성하기 위해도 환영합니다.
해결책
# sed script to change "foo" to "bar" only on the first occurrence
1{x;s/^/first/;x;}
1,/foo/{x;/first/s///;x;s/foo/bar/;}
#---end of script---
또는 원하는 경우 : 편집자 주 : 함께 작동합니다 암소 비슷한 일종의 영양 sed
뿐.
sed '0,/RE/s//to_that/' file
다른 팁
"Apple"의 첫 번째 발생 만 "바나나"로 대체 할 SED 스크립트를 작성하십시오.
예제 입력 : 출력 :
Apple Banana
Orange Orange
Apple Apple
이것은 간단한 스크립트입니다. 편집자 주 : 함께 작동합니다 암소 비슷한 일종의 영양 sed
뿐.
sed '0,/Apple/{s/Apple/Banana/}' filename
sed '0,/pattern/s/pattern/replacement/' filename
이것은 나를 위해 효과가있었습니다.
예시
sed '0,/<Menu>/s/<Menu>/<Menu><Menu>Sub menu<\/Menu>/' try.txt > abc.txt
편집자 주 : 둘 다 함께 작동합니다 암소 비슷한 일종의 영양 sed
뿐.
an 개요 많은 도움이되는 많은 것들 기존 답변, 보완 설명:
여기서 예제는 단순화 된 사용 사례를 사용합니다. 첫 번째 일치 선에서만 'foo'라는 단어를 'bar'로 바꾸십시오.
사용으로 인해 ANSI C- 인용 스트링 ($'...'
) 샘플 입력 라인을 제공하려면 bash
, ksh
, 또는 zsh
쉘로 가정됩니다.
암소 비슷한 일종의 영양 sed
뿐:
벤 호프스타인의 Anwswer GNU가 제공한다는 것을 보여줍니다 확대 ~로 posix 사양 sed
이는 다음 2 주소 양식을 허용합니다. 0,/re/
(re
여기서 임의의 정규 표현을 나타냅니다).
0,/re/
Regex를 허용합니다 성냥 첫 번째 줄에서도. 다시 말해 : 이러한 주소는 첫 번째 라인에서 일치하는 라인을 포함하여 범위를 만듭니다. re
- 이든 re
1 라인 또는 후속 라인에서 발생합니다.
- 이것을 POSIX 호환 양식과 대조하십시오
1,/re/
, 첫 번째 라인에서 일치하는 라인을 포함하는 범위를 생성합니다.re
~에 후속 윤곽; 다시 말해 : 이것은 AN의 첫 번째 발생을 감지하지 않습니다re
그것이 발생하는 경우 일치합니다 첫 번째 선 그리고 또한 속기의 사용을 방지합니다//
가장 최근에 사용 된 Regex를 재사용하려면 (다음 지점 참조).[1]
결합 된 경우 a 0,/re/
주소 s/.../.../
(대체) 같은 정규 표현, 귀하의 명령은 효과적으로 대체를 수행합니다. 첫 번째 일치하는 라인 re
.
sed
편리한 것을 제공합니다 가장 최근에 적용된 정규 표현식을 재사용하기위한 바로 가기: an 비어 있는 구분기 쌍, //
.
$ sed '0,/foo/ s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
POSIX-FEATURES 전용 sed
BSD (MACOS)와 같은 sed
(또한 함께 일할 것입니다 암소 비슷한 일종의 영양 sed
):
부터 0,/re/
사용할 수 없습니다 1,/re/
감지하지 않습니다 re
첫 번째 줄에서 발생하는 경우 (위 참조) 첫 번째 줄에 대한 특별 처리가 필요합니다.
Mikhailvs의 답변 이 기술을 언급하고 여기에 구체적인 예를 들어 있습니다.
$ sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
메모:
빈 regex
//
바로 가기는 여기에서 두 번 사용됩니다. 범위의 끝점에 대해 한 번, 그리고s
전화; 두 경우 모두 Regexfoo
암시 적으로 재사용하여 복제 할 필요가 없어서 더 짧고 유지 보수가 가능한 코드를 모두 만듭니다.posix
sed
라벨의 이름 이후 또는 생략과 같은 특정 기능 후에는 실제 신축이 필요합니다.t
여기; 스크립트를 여러 가지로 전략적으로 분할합니다-e
옵션은 실제 최신 라인을 사용하는 대안입니다.-e
Newline이 일반적으로 가야하는 스크립트 청크.
1 s/foo/bar/
대체 foo
첫 번째 줄에만 발견 된 경우에만. 그렇다면, t
스크립트 끝까지 분기 (라인에 남아있는 명령을 건너 뜁니다). (그만큼 t
기능 분기는 가장 최근에만 라벨에 분기됩니다. s
전화는 실제 대체를 수행했습니다. 여기의 경우와 마찬가지로 레이블이 없으면 스크립트의 끝이 분기됩니다).
이런 일이 발생하면 범위 주소 1,//
, 일반적으로 첫 번째 발생을 찾습니다 라인 2에서 시작합니다, 할 것이다 ~ 아니다 일치하면 범위가 있습니다 ~ 아니다 현재 라인이 이미있을 때 주소가 평가되기 때문에 처리됩니다. 2
.
반대로, 1 라인에 일치하지 않으면 1,//
~ 할 것이다 입력하고 진정한 첫 경기를 찾을 것입니다.
순 효과는 GNU와 동일합니다 sed
'에스 0,/re/
: 첫 번째 행이나 다른 행에서 발생하든 첫 번째 발생 만 대체됩니다.
비 범위 접근법
포통의 대답 시연 고리 기법 저것 범위의 필요성을 우회하십시오; 그가 사용하기 때문에 암소 비슷한 일종의 영양 sed
구문, 여기에 있습니다 POSIX- 호환 당량:
루프 기술 1 : 첫 경기에서 대체를 수행하십시오. 나머지 라인을 단순히 인쇄하는 루프를 입력하십시오.:
$ sed -e '/foo/ {s//bar/; ' -e ':a' -e '$!{n;ba' -e '};}' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
루프 기술 2, for 작은 파일 만: 전체 입력을 메모리에 읽은 다음 하나의 대체를 수행하십시오..
$ sed -e ':a' -e '$!{N;ba' -e '}; s/foo/bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
[1] 1.61803 무슨 일이 일어나는지에 대한 예를 제공합니다 1,/re/
, 후속 유무에 관계없이 s//
:
- sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'
수율 $'1bar\n2bar'
; 즉, 둘 다 라인 번호 때문에 라인이 업데이트되었습니다 1
1 라인과 레즈와 일치합니다 /foo/
- 범위의 끝 - 그런 다음 다음 선. 그러므로, 둘 다 이 경우 라인이 선택됩니다 s/foo/bar/
대체는 둘 다에서 수행됩니다.
- sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo'
실패합니다: 와 함께 sed: first RE may not be empty
(BSD/MACOS) 및 sed: -e expression #1, char 0: no previous regular expression
(GNU), 1 라인이 처리되고 있기 때문에 (라인 번호로 인해 1
범위를 시작), Regex는 아직 적용되지 않았습니다. //
아무것도 언급하지 않습니다.
GNU를 제외하고 sed
특별한 0,/re/
통사론, 어느 a로 시작하는 범위 줄 번호 효과적으로 사용을 배제합니다 //
.
당신은 awk를 사용하여 비슷한 일을 할 수 있습니다 ..
awk '/#include/ && !done { print "#include \"newfile.h\""; done=1;}; 1;' file.c
설명:
/#include/ && !done
라인이 "#include"와 일치 할 때 {} 사이에 action 문을 실행하고 우리는 아직 처리하지 않았습니다.
{print "#include \"newfile.h\""; done=1;}
이 인쇄 #include "newfile.h"는 인용문을 피해야합니다. 그런 다음 완료 변수를 1로 설정하므로 더 이상 포함되지 않습니다.
1;
이것은 "라인 인쇄"를 의미합니다. 빈 액션 기본값은 $ 0 인쇄하여 전체 라인을 인쇄합니다. SED IMO보다 이해하기 쉬운 하나의 라이너 :-)
상당히 포괄적 인 답변 모음 linuxtopia sed faq. 또한 사람들이 제공 한 일부 답변이 GNU가 아닌 SED와 함께 작동하지 않을 것임을 강조합니다.
sed '0,/RE/s//to_that/' file
비 GNU 버전에서는해야합니다
sed -e '1s/RE/to_that/;t' -e '1,/RE/s//to_that/'
그러나이 버전은 GNU SED에서 작동하지 않습니다.
다음은 다음과 같이 작동하는 버전입니다.
-e '/RE/{s//to_that/;:a' -e '$!N;$!ba' -e '}'
전:
sed -e '/Apple/{s//Banana/;:a' -e '$!N;$!ba' -e '}' filename
마지막에 발생 횟수 만 추가하십시오.
sed s/#include/#include "newfile.h"\n#include/1
#!/bin/sed -f
1,/^#include/ {
/^#include/i\
#include "newfile.h"
}
이 스크립트가 작동하는 방법 : 1과 첫 줄 사이의 줄 #include
(1 행 후), 라인이 시작하는 경우 #include
, 지정된 선을 선발하십시오.
그러나 첫 번째 경우 #include
1 행에 있고 1 행 1과 다음 후속에 있습니다. #include
라인이 배정됩니다. GNU를 사용하는 경우 sed
, 그것은 어디에도 확장이 있습니다 0,/^#include/
(대신에 1,
) 옳은 일을 할 것입니다.
가능한 해결책 :
/#include/!{p;d;}
i\
#include "newfile.h"
:
n
b
설명:
- #include를 찾을 때까지 줄을 읽고이 선을 인쇄 한 다음 새주기를 시작합니다.
- 새로운 포함 라인을 삽입하십시오
- 단지 라인을 읽는 루프를 입력합니다 (기본적으로 SED는이 라인도 인쇄 할 것입니다). 여기에서 스크립트의 첫 번째 부분으로 돌아 가지 않을 것입니다.
나는 이것이 오래된 게시물이라는 것을 알고 있지만 사용했던 솔루션이있었습니다.
grep -E -m 1 -n 'old' file | sed 's/:.*$//' - | sed 's/$/s\/old\/new\//' - | sed -f - file
기본적으로 Grep을 사용하여 첫 번째 발생을 찾아서 중지하십시오. 또한 인쇄 라인 번호, 즉 5 : 라인. SED에 파이프를 파이프하고 다음을 제거하십시오. s/.*을 추가하는 SED로 파이프를 파일에서 바꾸는 1 줄 스크립트를 제공합니다.
따라서 regex = #include 및 replare = blah이고 첫 번째 발생 Grep가 5 행에있는 경우 마지막 SED로 파이프 된 데이터는 5S/./ blah/입니다.
모든 라인에서 첫 번째 발생을 위해 캐릭터를 대체하기 위해 여기에 온 경우 다음을 사용하십시오.
sed '/old/s/old/new/1' file
-bash-4.2$ cat file
123a456a789a
12a34a56
a12
-bash-4.2$ sed '/a/s/a/b/1' file
123b456a789a
12b34a56
b12
예를 들어 1에서 2를 변경하면 두 번째 A를 모두 대신 교체 할 수 있습니다.
나는 awk 스크립트로 이것을 할 것이다 :
BEGIN {i=0}
(i==0) && /#include/ {print "#include \"newfile.h\""; i=1}
{print $0}
END {}
그런 다음 awk로 실행하십시오.
awk -f awkscript headerfile.h > headerfilenew.h
조잡 할 수도 있습니다. 저는 이것에 익숙하지 않습니다.
대안적인 제안으로 당신은 ed
명령.
man 1 ed
teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'
# for in-place file editing use "ed -s file" and replace ",p" with "w"
# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
H
/# *include/i
#include "newfile.h"
.
,p
q
EOF
마침내 RSS 피드에서 각 항목에 고유 한 타임 스탬프를 삽입하는 데 사용되는 Bash 스크립트 에서이 작업을 수행했습니다.
sed "1,/====RSSpermalink====/s/====RSSpermalink====/${nowms}/" \
production-feed2.xml.tmp2 > production-feed2.xml.tmp.$counter
첫 번째 발생 만 변경합니다.
${nowms}
Perl 스크립트로 설정된 밀리 초의 시간입니다. $counter
스크립트 내에서 루프 컨트롤에 사용되는 카운터입니다. \
다음 줄에서 명령을 계속할 수 있습니다.
파일을 읽고 stdout을 작업 파일로 리디렉션합니다.
내가 이해하는 방식, 1,/====RSSpermalink====/
범위 제한을 설정하여 언제 멈출 때 SED에게 말한 다음 s/====RSSpermalink====/${nowms}/
첫 번째 문자열을 두 번째 문자열로 바꾸는 친숙한 SED 명령입니다.
제 경우에는 명령을 이중 인용 자국에 넣어 변수가있는 bash 스크립트로 사용하고 있습니다.
사용 freebsd ed
그리고 피하십시오 ed
"없음"오류가없는 경우. include
처리 할 파일의 명령문 :
teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'
# using FreeBSD ed
# to avoid ed's "no match" error, see
# *emphasized text*http://codesnippets.joyent.com/posts/show/11917
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
H
,g/# *include/u\
u\
i\
#include "newfile.h"\
.
,p
q
EOF
이것은 당신에게 효과가있을 수 있습니다 (gnu sed) :
sed -si '/#include/{s//& "newfile.h\n&/;:a;$!{n;ba}}' file1 file2 file....
또는 메모리가 문제가되지 않는 경우 :
sed -si ':a;$!{N;ba};s/#include/& "newfile.h\n&/' file1 file2 file...
GNU sed s -z
수있는 옵션을 프로세스 전체에 파일 경우 그것은 단지 하나의 라인입니다.는 방법 s/…/…/
만 교체하는 첫 번째 매치에서는 전체 파일입니다.기억하십시오: s/…/…/
체는 첫 번째 매치에서 각 라인,하지만 -z
옵션 sed
전체 파일 하나로 라인입니다.
sed -z 's/#include/#include "newfile.h"\n#include'
일반적인 경우에 당신은 다시 작성 sed 표현 이후 패턴이 이제 공간을 보유하고 전체 파일을 대신 하나의 라인입니다.몇 가지 예:
s/text.*//
다음과 같이 다시 작성할 수 있습니다s/text[^\n]*//
.[^\n]
치는 모든 것 를 제외하고 줄 바꿈 문자입니다.[^\n]*
치는 모든 기후text
까지 줄 바꿈에 도달합니다.s/^text//
다음과 같이 다시 작성할 수 있습니다s/(^|\n)text//
.s/text$//
다음과 같이 다시 작성할 수 있습니다s/text(\n|$)//
.
다음 명령은 파일 내에서 문자열의 첫 번째 발생을 제거합니다. 빈 줄도 제거됩니다. XML 파일에 표시되지만 모든 파일에서 작동합니다.
XML 파일로 작업하고 태그를 제거하려는 경우 유용합니다. 이 예에서는 "istag"태그의 첫 번째 발생을 제거합니다.
명령:
sed -e 0,/'<isTag>false<\/isTag>'/{s/'<isTag>false<\/isTag>'//} -e 's/ *$//' -e '/^$/d' source.txt > output.txt
소스 파일 (source.txt)
<xml>
<testdata>
<canUseUpdate>true</canUseUpdate>
<isTag>false</isTag>
<moduleLocations>
<module>esa_jee6</module>
<isTag>false</isTag>
</moduleLocations>
<node>
<isTag>false</isTag>
</node>
</testdata>
</xml>
결과 파일 (output.txt)
<xml>
<testdata>
<canUseUpdate>true</canUseUpdate>
<moduleLocations>
<module>esa_jee6</module>
<isTag>false</isTag>
</moduleLocations>
<node>
<isTag>false</isTag>
</node>
</testdata>
</xml>
추신 : Solaris Sunos 5.10 (꽤 오래된)에서는 효과가 없었지만 Linux 2.6, SED 버전 4.1.5에서 작동합니다.
새로운 것은 없지만 아마도 조금 더 구체적인 대답 : sed -rn '0,/foo(bar).*/ s%%\1%p'
예시: xwininfo -name unity-launcher
다음과 같은 출력을 생성합니다.
xwininfo: Window id: 0x2200003 "unity-launcher"
Absolute upper-left X: -2980
Absolute upper-left Y: -198
Relative upper-left X: 0
Relative upper-left Y: 0
Width: 2880
Height: 98
Depth: 24
Visual: 0x21
Visual Class: TrueColor
Border width: 0
Class: InputOutput
Colormap: 0x20 (installed)
Bit Gravity State: ForgetGravity
Window Gravity State: NorthWestGravity
Backing Store State: NotUseful
Save Under State: no
Map State: IsViewable
Override Redirect State: no
Corners: +-2980+-198 -2980+-198 -2980-1900 +-2980-1900
-geometry 2880x98+-2980+-198
Window ID 추출 xwininfo -name unity-launcher|sed -rn '0,/^xwininfo: Window id: (0x[0-9a-fA-F]+).*/ s%%\1%p'
생산 :
0x2200003
posixly (SED에서도 유효) 만 하나 REGEX 사용, 한 줄에 대해서만 메모리가 필요합니다 (평소와 같이) :
sed '/\(#include\).*/!b;//{h;s//\1 "newfile.h"/;G};:1;n;b1'
설명 :
sed '
/\(#include\).*/!b # Only one regex used. On lines not matching
# the text `#include` **yet**,
# branch to end, cause the default print. Re-start.
//{ # On first line matching previous regex.
h # hold the line.
s//\1 "newfile.h"/ # append ` "newfile.h"` to the `#include` matched.
G # append a newline.
} # end of replacement.
:1 # Once **one** replacement got done (the first match)
n # Loop continually reading a line each time
b1 # and printing it by default.
' # end of sed script.