답변:
# 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---
또는 원하는 경우 : 편집자 주 : GNU sed
에서만 작동 합니다.
sed '0,/foo/s//bar/' file
0,
에만 작동gnu sed
s//
- 즉, 빈 정규식 - 가장 최근에 적용 정규식 암시 적으로 재사용되는 것을 의미; 이 경우, RE
. 이 편리한 바로 가기는 s
통화 에서 범위 끝 정규 표현식을 복제 할 필요가 없음을 의미합니다 .
sed
전용 "바나나"에 의해 "애플"의 첫 번째 항목을 대체합니다 스크립트
예
Input: Output:
Apple Banana
Apple Apple
Orange Orange
Apple Apple
이것은 간단한 스크립트입니다. 편집자 주 : GNU sed
에서만 작동 합니다.
sed '0,/Apple/{s/Apple/Banana/}' input_filename
처음 두 파라미터 0
및 /Apple/
범위 지정된다. 는 s/Apple/Banana/
그 범위 내에서 실행되는 것입니다. 그래서 처음의 범위 내에서이 경우 "에서 ( 0
) 최대의 첫 번째 인스턴스에 Apple
교체 Apple
로 Banana
. 첫 번째 Apple
대체됩니다.
배경 : 전통에서 sed
범위 지정은 또한 "여기서 끝나지" "여기에서 시작"과 (포함). 그러나 가장 낮은 "시작"은 첫 번째 행 (1 행)이고 "여기서 끝"이 정규식 인 경우 "시작"이후 다음 행에서만 일치 시키려고 시도하므로 가능한 가장 빠른 끝은 행입니다. 2. 범위가 포함되므로 가능한 가장 작은 범위는 "2 라인"이고 가장 작은 시작 범위는 라인 1과 2 모두입니다 (즉, 라인 1에 발생하는 경우, 라인 2의 발생도 변경됩니다.이 경우에는 바람직하지 않습니다). ). GNU
sed는 시작을 "의사"로 지정 line 0
하여 범위의 끝 line 1
이 "첫 번째 행만" 의 범위가 될 수 있도록 자체 확장을 추가합니다.
또는 단순화 된 버전 (빈 RE 유사은 //
이전에 지정된 것을 재사용한다는 것을 의미하므로 다음과 같습니다).
sed '0,/Apple/{s//Banana/}' input_filename
중괄호는 명령에 대해 선택 사항s
이므로 다음과 같습니다.
sed '0,/Apple/s//Banana/' input_filename
이 모든 것은 GNU sed
에서만 작동 합니다.
homebrew를 사용하여 OS X에 GNU sed를 설치할 수도 있습니다 brew install gnu-sed
.
sed: 1: "…": bad flag in substitute command: '}'
sed -e '1s/Apple/Banana/;t' -e '1,/Apple/s//Banana/'
. @MikhailVS의 답변에서 (현재) 아래로 내려갑니다.
sed '0,/foo/s/foo/bar/'
sed: -e expression #1, char 3: unexpected
. '
sed '0,/pattern/s/pattern/replacement/' filename
이것은 나를 위해 일했습니다.
예
sed '0,/<Menu>/s/<Menu>/<Menu><Menu>Sub menu<\/Menu>/' try.txt > abc.txt
편집자 주 : 둘 다 GNU sed
에서만 작동 합니다.
sed '1,/pattern/s/pattern/replacement/' filename
Mac에서 "첫 번째 줄에 패턴이 나타나지 않을"경우에만 작동합니다. 이전 의견은 정확하지 않으므로 삭제하겠습니다. 자세한 내용은 여기 ( linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/… ) 에서 확인할 수 있습니다 . Andy의 대답은 GNU sed에서만 작동하지만 Mac에서는 그렇지 않습니다.
개요 많은 도움의 기존 답변 보완, 설명 :
여기서 예제는 단순화 된 사용 사례를 사용합니다. 첫 번째 일치하는 행에서만 단어 'foo'를 'bar'로 바꿉니다.
인해 사용에 ANSI C 따옴표 문자열 ( $'...'
) 샘플의 입력 라인을 제공하기 위해 bash
, ksh
또는 zsh
쉘로 가정한다.
GNU sed
만 :
벤 Hoffstein의 anwswer의 GNU가 제공하는 쇼 우리를 확장 받는 사람 에 대한 POSIX 사양sed
즉, 다음과 같은 수 2 주소 양식 : 0,/re/
( re
임의의 정규 표현식 여기를 나타냅니다).
0,/re/
첫 번째 줄에서도 정규 표현식을 일치 시킬 수 있습니다 . 다시 말해, 이러한 주소는 첫 번째 행에서 발생 re
하는지 re
또는 후속 행에서 발생 하는지에 관계없이 첫 번째 행에서 일치하는 행을 포함하여 그 사이의 범위를 만듭니다 .
1,/re/
범위를 생성하고, 그 1 라인에서 일치하고 라인까지 포함하여 그 일치 re
에 후속 라인; 즉 :이 의 첫 번째 항목 검색하지 않습니다 re
가 발생하는 일이 생기면 일치하는 1 라인 또한 속기의 사용을 방지 할//
가장 최근에 사용 된 정규식의 재사용을 (다음 사항 참조). 10,/re/
주소를 동일한 정규식 s/.../.../
을 사용 하는 (대체) 호출 과 결합하면 명령은 첫 번째 행과 일치 하는 대체 만 효과적으로 수행합니다 . 편리한 제공하는 가장 최근에 적용되는 정규 표현식 재사용 바로 가기 : 빈 , 구분 기호 쌍 .re
sed
//
$ 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
sed
BSD (macOS)와 같은 POSIX 기능 만 해당sed
( GNU 에서도 작동 sed
) :
때문에 0,/re/
사용할 수 없습니다 양식이 1,/re/
감지되지 않습니다 re
그것 (위 참조) 매우 첫 번째 줄에 발생하는 발생하는 경우, 1 라인에 대한 특별한 처리가 필요합니다 .
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
노트 :
빈 정규식 //
바로 가기는 여기에서 두 번 사용됩니다. 범위의 끝점에 대해 한 번, s
호출 에서 한 번 ; 두 경우 모두 정규식 foo
이 암시 적으로 재사용되므로 복제 할 필요가 없으므로 코드가 짧고 유지 보수가 쉽습니다.
POSIX sed
는 여기에서와 같이 레이블 이름이나 생략과 같은 특정 기능 뒤에 실제 줄 바꿈이 필요 t
합니다. 전략적으로 스크립트를 여러 -e
옵션 으로 분할하는 것은 실제 줄 바꿈을 사용하는 대안 -e
입니다. 줄 바꿈이 일반적으로 필요한 곳에서 각 스크립트 청크를 종료하십시오 .
1 s/foo/bar/
foo
발견 된 경우 첫 번째 줄에서만 바꿉니다 . 그렇다면 t
스크립트 끝으로 분기합니다 (줄에 남아있는 명령을 건너 뜁니다). (이 t
함수는 가장 최근의 s
호출이 실제 대체를 수행 한 경우에만 레이블로 분기합니다. 레이블 이 없으면 여기에서와 같이 스크립트의 끝이 분기됩니다).
그렇게되면, 주소 범위 1,//
통상 최초로 출현 찾은 라인 (2)에서 시작은 의지 하지 일치 및 범위 의지 하지 전류 선 이미 때 어드레스가 평가되기 때문에, 처리 2
.
1 라인의 일치가 존재하지 않는 경우는 반대로 1,//
합니다 입력하고, 진정한 첫 경기를 찾을 수 있습니다.
순 효과는 GNU sed
의 경우와 동일 0,/re/
합니다. 첫 번째 행에서 발생하든 다른 행에서 발생하든 첫 번째 발생 만 바뀝니다.
비 범위 접근
potong의 답변 은 범위의 필요성을 우회하는 루프 기술 을 보여줍니다 . 그가 GNU 구문 을 사용하기 때문에 POSIX 호환 등가물은 다음 과 같습니다 . sed
루프 기술 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 : 전체 입력을 메모리로 읽은 다음 단일 대체를 수행하십시오 .
$ 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
정규 표현식 /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
범위를 시작하는 줄 번호로 인해 ) 정규 표현식이 아직 적용되지 않았으므로//
아무것도 언급하지 않습니다.
GNU sed
의 특수 0,/re/
구문을 제외 하고, 행 번호로 시작하는 모든 범위는을 효과적으로 사용할 수 없습니다 .
//
awk를 사용하여 비슷한 것을 할 수 있습니다.
awk '/#include/ && !done { print "#include \"newfile.h\""; done=1;}; 1;' file.c
설명:
/#include/ && !done
행이 "#include"와 일치하고 아직 처리하지 않은 경우 {} 사이에서 작업 문을 실행합니다.
{print "#include \"newfile.h\""; done=1;}
#include "newfile.h"를 출력합니다. 따옴표를 이스케이프 처리해야합니다. 그런 다음 done 변수를 1로 설정하므로 더 이상 포함을 추가하지 않습니다.
1;
이것은 "행 인쇄"를 의미합니다. 빈 작업은 기본적으로 $ 0를 인쇄하여 전체 행을 인쇄합니다. 하나의 라이너로 sed IMO보다 이해하기 쉽습니다 :-)
awk '/version/ && !done {print " \"version\": \"'${NEWVERSION}'\""; done=1;}; 1;' package.json
awk '/#include/ && !done { gsub(/#include/, "include \"newfile.h\""); done=1}; 1' file.c
linuxtopia sed FAQ 에 대한 답변의 포괄적 인 모음 . 또한 사람들이 제공 한 일부 답변이 비 sed 버전의 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
#!/bin/sed -f
1,/^#include/ {
/^#include/i\
#include "newfile.h"
}
이 스크립트의 작동 방식 : 1과 첫 번째 #include
(1 행 이후) 사이 의 행에서 행으로 시작 #include
하는 경우 지정된 행을 앞에 추가하십시오.
그러나 첫 번째 #include
줄 이 첫 번째 줄에 있으면 첫 번째 줄과 다음 줄 모두 #include
앞에 줄이 붙습니다. GNU를 사용 sed
하는 경우 0,/^#include/
(대신 대신 1,
) 올바른 작업을 수행 할 수 있는 확장명이 있습니다.
끝에 발생 횟수를 추가하십시오.
sed s/#include/#include "newfile.h"\n#include/1
sed
는 다음 [2addr]s/BRE/replacement/flags
과 같이 대체 명령 을 지정합니다. "플래그 값은 0 이상이어야합니다. n n 패턴 공간에서 발견 된 BRE 만 n 번째로 대체합니다." 따라서 적어도 POSIX 2008에서 후행 1
은 GNU sed
확장 이 아닙니다 . 실제로 SUS / POSIX 1997 표준 에서도이 기능 이 지원 되었기 때문에 2008 년에
가능한 해결책 :
/#include/!{p;d;}
i\
#include "newfile.h"
:a
n
ba
설명:
sed: file me4.sed line 4: ":" lacks a label
나는 이것이 오래된 게시물이라는 것을 알고 있지만, 내가 사용했던 해결책이 있었다.
grep -E -m 1 -n 'old' file | sed 's/:.*$//' - | sed 's/$/s\/old\/new\//' - | sed -f - file
기본적으로 grep을 사용하여 첫 번째 발생을 인쇄하고 중지하십시오. 또한 줄 번호를 인쇄하십시오 5:line
. sed에 파이프를 넣고 :와 그 이후의 것을 제거하면 줄 번호가 남습니다. s /.*/ replace를 종료 번호에 추가하는 sed로 파이프하면 파일에서 스크립트로 실행되도록 마지막 sed로 파이프되는 1 행 스크립트가 생성됩니다.
따라서 regex = #include
및 replace = blah
이고 grep이 찾은 첫 번째 행이 5 행에 있으면 마지막 sed로 파이프 된 데이터는입니다 5s/.*/blah/
.
첫 번째 행이 첫 번째 행에 있더라도 작동합니다.
sed -f -
일부는 그렇지 않은 것을 받아 들일만큼 영리 하지만 당신은 그 문제를 해결할 수 있습니다 :)
모든 사람이 자신과 같은 모든 줄에서 처음으로 문자를 교체하기 위해 여기에 온 사람이라면 다음을 사용하십시오.
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 만 모두 바꿀 수 있습니다.
's/a/b/'
의미 match a
하고,do just first match
for every matching line
GNU sed의 -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|$)//
.다른 제안으로 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
다음 명령은 파일에서 문자열의 첫 항목을 제거합니다. 빈 줄도 제거합니다. 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
(따라서 Solaris에서는 작동하지 않음). 이 정보를 삭제해야합니다. 실제로 대답했을 때 이미 4½ 세였던 질문에 고유 한 새로운 정보를 제공하지는 않습니다. 물론, 그것은 잘 작동하는 예를 가지고 있지만 질문에 대한 답변이 많은 것이라면 논쟁의 여지가 있습니다.
새로운 것은 아니지만 약간 더 구체적인 대답은 없습니다. 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
다음을 xwininfo -name unity-launcher|sed -rn '0,/^xwininfo: Window id: (0x[0-9a-fA-F]+).*/ s%%\1%p'
생성 하여 창 ID를 추출 합니다.
0x2200003
POSIXly (sed에서도 유효), 하나의 정규식 만 사용되며 한 줄에 대해서만 메모리가 필요합니다 (평소와 같이).
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.
여기에서 가능한 해결책은 소스 파일에 언급되지 않고 헤더를 포함하도록 컴파일러에 지시하는 것입니다. GCC에는 다음과 같은 옵션이 있습니다.
-include file
Process file as if "#include "file"" appeared as the first line of
the primary source file. However, the first directory searched for
file is the preprocessor's working directory instead of the
directory containing the main source file. If not found there, it
is searched for in the remainder of the "#include "..."" search
chain as normal.
If multiple -include options are given, the files are included in
the order they appear on the command line.
-imacros file
Exactly like -include, except that any output produced by scanning
file is thrown away. Macros it defines remain defined. This
allows you to acquire all the macros from a header without also
processing its declarations.
All files specified by -imacros are processed before all files
specified by -include.
Microsoft의 컴파일러에는 / FI (강제 포함) 옵션이 있습니다.
이 기능은 플랫폼 구성과 같은 일반적인 헤더에 유용합니다. 리눅스 커널의 Makefile -include
이 이것을 사용 합니다.