기존 #include 전에 추가 include 지시문으로 많은 수의 C ++ 소스 파일을 업데이트하고 싶습니다. 이런 종류의 작업에서는 일반적으로 sed와 함께 작은 bash 스크립트를 사용하여 파일을 다시 씁니다.
sed
모든 항목을 바꾸지 않고 파일에서 첫 번째 문자열 만 바꾸 려면 어떻게해야 합니까?
내가 사용하면
sed s/#include/#include "newfile.h"\n#include/
모든 #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---
또는 원하는 경우 : 편집자 주 : GNU sed
에서만 작동 합니다.
sed '0,/foo/s//bar/' file
답변
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 '0,/pattern/s/pattern/replacement/' filename
이것은 나를 위해 일했습니다.
예
sed '0,/<Menu>/s/<Menu>/<Menu><Menu>Sub menu<\/Menu>/' try.txt > abc.txt
편집자 주 : 둘 다 GNU sed
에서만 작동 합니다.
답변
개요 많은 도움의 기존 답변 보완, 설명 :
여기서 예제는 단순화 된 사용 사례를 사용합니다. 첫 번째 일치하는 행에서만 단어 ‘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
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보다 이해하기 쉽습니다 🙂
답변
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,
) 올바른 작업을 수행 할 수 있는 확장명이 있습니다.