sed를 사용하여 파일에서 첫 번째 항목 만 바꾸는 방법은 무엇입니까?


217

기존 #include 전에 추가 include 지시문으로 많은 수의 C ++ 소스 파일을 업데이트하고 싶습니다. 이런 종류의 작업에서는 일반적으로 sed와 함께 작은 bash 스크립트를 사용하여 파일을 다시 씁니다.

sed모든 항목을 바꾸지 않고 파일에서 첫 번째 문자열 만 바꾸 려면 어떻게해야 합니까?

내가 사용하면

sed s/#include/#include "newfile.h"\n#include/

모든 #include를 대체합니다.

같은 것을 달성하기위한 대안 제안도 환영합니다.

답변:


135
 # 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 

출처


86
나는 '또는 원하는 경우'솔루션을 선호한다고 생각합니다. 또한 답변을 설명하고 답변을 질문에 직접 제시 한 다음 일반화하기보다는 일반화하는 것이 좋습니다. 그러나 좋은 대답입니다.
Jonathan Leffler

7
참고로 Mac 사용자의 경우 0을 1로 바꿔야합니다. sed '1, / RE / s // to_that /'파일
mhost

1
@mhost 아니요, 패턴이 라인 # 1에서 발견되면 교체하는 것보다 패턴이 다른 라인에있는 경우가 아니라 여전히 처음 발견 된 패턴입니다. 이 것을 PS 그것은 언급해야 0,에만 작동gnu sed
Jotne

11
누군가가 '또는 당신이 prefeer 경우'솔루션을 설명해 주시겠습니까? "from"패턴을 어디에 넣을 지 모르겠습니다.
Jean-Luc Nacif Coelho

3
장 - LucNacifCoelho @ : 사용 s//- 즉, 정규식 - 가장 최근에 적용 정규식 암시 적으로 재사용되는 것을 의미; 이 경우, RE. 이 편리한 바로 가기는 s통화 에서 범위 끝 정규 표현식을 복제 할 필요가 없음을 의미합니다 .
mklement0

289

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교체 AppleBanana. 첫 번째 Apple대체됩니다.

배경 : 전통에서 sed범위 지정은 또한 "여기서 끝나지" "여기에서 시작"과 (포함). 그러나 가장 낮은 "시작"은 첫 번째 행 (1 행)이고 "여기서 끝"이 정규식 인 경우 "시작"이후 다음 행에서만 일치 시키려고 시도하므로 가능한 가장 빠른 끝은 행입니다. 2. 범위가 포함되므로 가능한 가장 작은 범위는 "2 라인"이고 가장 작은 시작 범위는 라인 1과 2 모두입니다 (즉, 라인 1에 발생하는 경우, 라인 2의 발생도 변경됩니다.이 경우에는 바람직하지 않습니다). ). GNUsed는 시작을 "의사"로 지정 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.


166
인간 언어로 번역 : 0 행에서 시작하여 'Apple'과 일치 할 때까지 계속하고 중괄호로 대치하십시오. cfr : grymoire.com/Unix/Sed.html#uh-29
mariotomo

8
OS X에서 다음을 얻습니다sed: 1: "…": bad flag in substitute command: '}'
ELLIOTTCABLE

5
OS X에서 @ELLIOTTCABLE을 사용하십시오 sed -e '1s/Apple/Banana/;t' -e '1,/Apple/s//Banana/'. @MikhailVS의 답변에서 (현재) 아래로 내려갑니다.
djb

8
대괄호 없이도 작동합니다 :sed '0,/foo/s/foo/bar/'
Innokenty

5
나는 이것을 얻습니다 sed: -e expression #1, char 3: unexpected . '
Jonathan

56
sed '0,/pattern/s/pattern/replacement/' filename

이것은 나를 위해 일했습니다.

sed '0,/<Menu>/s/<Menu>/<Menu><Menu>Sub menu<\/Menu>/' try.txt > abc.txt

편집자 주 : 둘 다 GNU sed 에서만 작동 합니다.


2
@Landys 이것은 여전히 ​​다른 줄의 인스턴스를 대체합니다. 첫 번째 인스턴스뿐만 아니라
Sarat

1
@sarat 네, 그렇습니다. sed '1,/pattern/s/pattern/replacement/' filenameMac에서 "첫 번째 줄에 패턴이 나타나지 않을"경우에만 작동합니다. 이전 의견은 정확하지 않으므로 삭제하겠습니다. 자세한 내용은 여기 ( linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/… ) 에서 확인할 수 있습니다 . Andy의 대답은 GNU sed에서만 작동하지만 Mac에서는 그렇지 않습니다.
랜디스

45

개요 많은 도움의 기존 답변 보완, 설명 :

여기서 예제는 단순화 된 사용 사례를 사용합니다. 첫 번째 일치하는 행에서만 단어 'foo'를 'bar'로 바꿉니다.
인해 사용에 ANSI C 따옴표 문자열 ( $'...') 샘플의 입력 라인을 제공하기 위해 bash, ksh또는 zsh쉘로 가정한다.


GNU sed 만 :

벤 Hoffstein의 anwswer의 GNU가 제공하는 쇼 우리를 확장 받는 사람 에 대한 POSIX 사양sed 즉, 다음과 같은 수 2 주소 양식 : 0,/re/( re임의의 정규 표현식 여기를 나타냅니다).

0,/re/첫 번째 줄에서도 정규 표현식을 일치 시킬 수 있습니다 . 다시 말해, 이러한 주소는 첫 번째 행에서 발생 re하는지 re또는 후속 행에서 발생 하는지에 관계없이 첫 번째 행에서 일치하는 행을 포함하여 그 사이의 범위를 만듭니다 .

  • POSIX의 호환 형 명암이 1,/re/범위를 생성하고, 그 1 라인에서 일치하고 라인까지 포함하여 그 일치 re후속 라인; 즉 :이 의 첫 번째 항목 검색하지 않습니다 re가 발생하는 일이 생기면 일치하는 1 라인 또한 속기의 사용을 방지 할// 가장 최근에 사용 된 정규식의 재사용을 (다음 사항 참조). 1

0,/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

sedBSD (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/구문을 제외 하고, 행 번호로 시작하는 모든 범위는을 효과적으로 사용할 수 없습니다 . //


25

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보다 이해하기 쉽습니다 :-)


4
이 답변에 의존 나오지 솔루션보다 더 많은 휴대용 GNU 나오지도 등 (예 : OS-X에서 나오지도 짜증!)
제이 테일러

1
이것은 실제로 더 이해하기 쉽지만 나 대신 그것을 대체하는 대신 줄을 추가합니다. 사용 된 명령 : awk '/version/ && !done {print " \"version\": \"'${NEWVERSION}'\""; done=1;}; 1;' package.json
시리얼 킬러

여기에서도 가장 이해하기 쉬운 명령이지만 찾은 문자열을 바꾸는 대신 찾은 문자열 위에 줄을 추가합니다.
Flion

1
대답은 꽤 읽을 수 있습니다. 새 줄을 추가하는 대신 문자열을 대체하는 내 버전이 있습니다. awk '/#include/ && !done { gsub(/#include/, "include \"newfile.h\""); done=1}; 1' file.c
Orsiris de Jong

18

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

실제로 Ubuntu Linux v16 및 ​​FreeBSD v10.2에서 작동하는지 테스트했습니다. 감사합니다.
Sopalajo de Arrierez 2016 년

12
#!/bin/sed -f
1,/^#include/ {
    /^#include/i\
#include "newfile.h"
}

이 스크립트의 작동 방식 : 1과 첫 번째 #include(1 행 이후) 사이 의 행에서 행으로 시작 #include하는 경우 지정된 행을 앞에 추가하십시오.

그러나 첫 번째 #include줄 이 첫 번째 줄에 있으면 첫 번째 줄과 다음 줄 모두 #include앞에 줄이 붙습니다. GNU를 사용 sed하는 경우 0,/^#include/(대신 대신 1,) 올바른 작업을 수행 할 수 있는 확장명이 있습니다.


11

끝에 발생 횟수를 추가하십시오.

sed s/#include/#include "newfile.h"\n#include/1

7
불행히도 이것은 작동하지 않습니다. 파일의 첫 번째 행이 아닌 파일의 각 행에서 첫 번째 발생을 바꿉니다.
David Dibben

1
또한 표준 sed 기능이 아닌 GNU sed 확장입니다.
Jonathan Leffler

10
흠 ... 시간이지나갑니다. POSIX 2008/2013 for sed는 다음 [2addr]s/BRE/replacement/flags과 같이 대체 명령 을 지정합니다. "플래그 값은 0 이상이어야합니다. n n 패턴 공간에서 발견 된 BRE 만 n 번째로 대체합니다." 따라서 적어도 POSIX 2008에서 후행 1은 GNU sed확장 이 아닙니다 . 실제로 SUS / POSIX 1997 표준 에서도이 기능 이 지원 되었기 때문에 2008 년에
나빠 졌었

7

가능한 해결책 :

    /#include/!{p;d;}
    i\
    #include "newfile.h"
    :a
    n
    ba

설명:

  • #include를 찾을 때까지 행을 읽고이 행을 인쇄 한 다음 새주기를 시작하십시오.
  • 새로운 포함 라인을 삽입
  • 줄을 읽는 루프를 입력하십시오 (기본적으로 sed는 이러한 줄을 인쇄합니다). 여기서 스크립트의 첫 부분으로 돌아 가지 않습니다.

sed: file me4.sed line 4: ":" lacks a label
rogerdpack

최근 sed 버전에서 변경된 사항이 있고 빈 레이블은 더 이상 허용되지 않습니다. 답변을 업데이트 함
mitchnull

4

나는 이것이 오래된 게시물이라는 것을 알고 있지만, 내가 사용했던 해결책이 있었다.

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/.

첫 번째 행이 첫 번째 행에 있더라도 작동합니다.


나는 s 및 linenumber 이외의 것을 사용하여 여러 줄로 된 sed 스크립트 또는 sed 명령을 완전히 싫어 하므로이 접근법을 사용합니다. 다음은 유스 케이스에 사용 된 것입니다 (bash와 함께 작동) : filepath = / etc / hosts; patt = '^ \ (127 \ .0 \ .0 \ .1. * \)'; repl = '\ 1 newhostalias'; sed $ (IFS = : linearray = ($ (grep -E -m 1 -n "$ patt" "$ filepath")) && echo $ {linearray [0]}) s / "$ patt"/ "$ repl" / "$ filepath"
parity3

효과가있다. sed의 경우에만 sed -f -일부는 그렇지 않은 것을 받아 들일만큼 영리 하지만 당신은 그 문제를 해결할 수 있습니다 :)
rogerdpack

3

모든 사람이 자신과 같은 모든 줄에서 처음으로 문자를 교체하기 위해 여기에 온 사람이라면 다음을 사용하십시오.

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 만 모두 바꿀 수 있습니다.


2
당신은이 모든 수행 할 필요가 없습니다 's/a/b/'의미 match a하고,do just first match for every matching line
Samveen

저는 Samveen과 함께 있습니다. 또한 이것은 여기에서 묻는 질문에 대답하지 않습니다 . 이 답변을 삭제하는 것이 좋습니다.
Socowi

문제는 "파일에서 첫 번째 발생"이 아니라 "라인에서 첫 번째 발생"이 아니라
Manuel Romeiro

3

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|$)//.

2

나는 awk 스크립트로 이것을 할 것이다 :

BEGIN {i=0}
(i==0) && /#include/ {print "#include \"newfile.h\""; i=1}
{print $0}    
END {}

그런 다음 awk로 실행하십시오.

awk -f awkscript headerfile.h > headerfilenew.h

어리석은 것일 수도 있습니다.


2

다른 제안으로 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

2

마침내 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 스크립트에서 명령을 사용하고 있습니다.


2

처리 할 파일에 명령문 이없는 경우 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

이것은 timo답변 과 매우 유사 하지만 1 년 후에 추가되었습니다.
Jonathan Leffler

2

이것은 당신을 위해 일할 수 있습니다 (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...

0

다음 명령은 파일에서 문자열의 첫 항목을 제거합니다. 빈 줄도 제거합니다. 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에서는 작동합니다


이것은 GNU에서만 작동한다는 동일한 경고와 함께 많은 이전 답변과 동일한 기본 아이디어와 매우 비슷합니다 sed(따라서 Solaris에서는 작동하지 않음). 이 정보를 삭제해야합니다. 실제로 대답했을 때 이미 4½ 세였던 질문에 고유 한 새로운 정보를 제공하지는 않습니다. 물론, 그것은 잘 작동하는 예를 가지고 있지만 질문에 대한 답변이 많은 것이라면 논쟁의 여지가 있습니다.
Jonathan Leffler

0

새로운 것은 아니지만 약간 더 구체적인 대답은 없습니다. 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

0

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.

0

유스 케이스는 아마 당신의 발행 수는 파일 전체에 분산되어있을 수 있습니다,하지만 당신은 알고 당신의 유일한 관심사는 처음 10, 20 또는 100 라인입니다.

그런 다음 OP의 문구가 먼저 고려 되더라도 단순히 해당 라인에 주소를 지정하면 문제가 해결 됩니다.

sed '1,10s/#include/#include "newfile.h"\n#include/'

0

여기에서 가능한 해결책은 소스 파일에 언급되지 않고 헤더를 포함하도록 컴파일러에 지시하는 것입니다. 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이 이것을 사용 합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.