문제

하고 싶의 큰 숫자를 업데이트 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 전화; 두 경우 모두 Regex foo 암시 적으로 재사용하여 복제 할 필요가 없어서 더 짧고 유지 보수가 가능한 코드를 모두 만듭니다.

  • 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.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top