파일에서 찾기 및 바꾸기 및 파일 덮어 쓰기가 작동하지 않아 파일을 비 웁니다.


604

명령 줄을 통해 HTML 파일에서 찾기 및 바꾸기를 실행하고 싶습니다.

내 명령은 다음과 같습니다.

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

이것을 실행하고 나중에 파일을 보면 비어 있습니다. 내 파일의 내용을 삭제했습니다.

파일을 다시 복원 한 후 이것을 실행하면 :

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdout파일의 내용이고, 찾아 실행 된 대체합니다.

왜 이런 일이 발생합니까?


13
펄 대안 :perl -pi -w -e 's/STRING_TO_REPLACE/REPLACE_WITH/g;' index.html
Gjorgji Tashkovski

sed문자열을 찾고 전체 줄을 바꾸는 많은 관련 명령 : stackoverflow.com/questions/11245144/…
cregox

답변:


917

쉘이 보고 > index.html명령 줄에서 파일이 열립니다 index.html에 대한 쓰기 모든 이전 내용을 닦아.

이 문제를 해결하려면 -i옵션 을 전달하여 sed변경 사항을 인라인으로 만들고 원본 파일의 백업을 작성하여 변경 작업을 수행해야합니다.

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

.bak가 없으면 Mac OSX와 같은 일부 플랫폼에서 명령이 실패합니다.


20
아마 truncates the file대신 말하는 opens the file것이 더 명확합니다.
Mikel

12
적어도 내 Mac에서는 첫 번째 제안이 작동하지 않습니다 ... 파일에서 전체 대체를 수행하는 경우 확장자를 지정해야합니다. 최소한 길이가 0 인 확장명을 전달할 수 있습니다. sed -i ''s / STRING_TO_REPLACE / STRING_TO_REPLACE_IT / g index.html
Tom Lianza

5
변수 sed -i.bak 's /'$ search '/'$ replace '/ g'index.html
Fatima Zohra

33
osx에서 빈 문자열 ''을 -i의 매개 변수로 사용하십시오.sed -i '' 's/blah/xx/g'
Pierre Houston

4
하지만 당신은 무엇인가 .bak후에 sed -i?
Patrizio Bertoni

210

대안적이고 유용한 패턴은 다음과 같습니다.

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

이것은 -i옵션 을 사용하지 않고 거의 동일한 효과를 가지며 , sed 스크립트가 어떤 이유로 실패하면 입력 파일이 방해받지 않는다는 것을 의미합니다. 또한 편집에 성공하면 백업 파일이 남아 있지 않습니다. 이런 종류의 관용구는 Makefile에서 유용 할 수 있습니다.

상당히 많은 썰매가 -i옵션을 가지고 있지만 전부는 아닙니다. posix sed는 그렇지 않은 것입니다. 따라서 이식성을 목표로하는 경우에는 피하는 것이 가장 좋습니다.


9
백업 파일이없고 편집이 실패한 경우 입력 파일을 방해하지 않으면 +1입니다. Mac에서 완벽하게 작동했습니다.
Mike Grace

나를 위해 완벽하게 일했습니다. 감사합니다! (Mac에서)
관심

1
이것은 Ubuntu Server 14.04 sed -i에서 파일을 제로 아웃하는 곳에서 완벽하게 작동했습니다.
Chris Giddings

2
매우 사소한 향상 :... && mv index.html{.tmp,}
EdwardGarson

5
@EdwardGarson 실제로, 그것은 내가 타이핑하는 경우에 내가 사용하는 것일 것입니다. 더 깔끔 sh하다고 생각 하지만 (정확히 기억한다면) 그 {...}확장 이 없습니다 . Makefile에서는을 사용 sh하는 것이 아니라 사용할 수 있으므로 bash이식성 (또는 posixness)을 목표로하는 경우 해당 구성을 피해야합니다.
Norman Grey

95
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

이것은 index.html 파일을 전체적으로 대체합니다. 문자열을 인용하면 쿼리 및 공백의 공백 문제를 방지 할 수 있습니다.


57

sed의 -i 옵션을 사용하십시오. 예 :

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html

이것은 무엇을 의미 하는가? sed : -i는 stdin과 함께 사용할 수 없습니다
sheetal

2
공백이 포함 된 패턴은 따옴표로 묶어야합니다. –'s/STRING_TO_REPLACE/REPLACE_WITH/g'
Doug Thompson

@sheetal : 파일의-i 내부 편집을 수행 하므로 stdin 입력 과 결합하는 것은 의미가 없습니다 .
mklement0

이것은 macOS에서는 작동하지만 Arch Linux에서는 그렇지 않습니다.
xdevs23

-e가 없으면 허용 된 답변이 MacOS, Catalina에서 작동하지 않습니다. -e를 사용하면 작동합니다.
cwhiii

18

여러 파일을 변경하고 각 백업을 * .bak로 저장하려면 다음을 수행하십시오.

perl -p -i -e "s/\|/x/g" *  

디렉토리에있는 모든 파일을 가지고 대체 할 |x 는 "펄 파이"라고이 (쉽게 파이)


1
태그뿐만 아니라 문제 진술을 기꺼이 보려는 사람을 만나서 반갑습니다. OP는 sed요구 사항으로 지정하지 않았으며 도구가 이미 시도한 대로만 사용했습니다.
user7412956


6
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

추가 할 링크가 있다면 이것을 시도하십시오. 위와 같이 URL을 검색하고 (https로 시작하고 여기서 .com으로 끝남) URL 문자열로 바꾸십시오. $pub_url여기 에 변수를 사용했습니다 . s여기서는 검색을 g의미하며 전체 교체를 의미합니다.

효과가있다 !


6

경고 : 이것은 위험한 방법입니다! 그것은 리눅스에서 i / o 버퍼를 남용하고 특정 버퍼링 옵션으로 작은 파일에서 작동하도록 관리합니다. 흥미로운 호기심입니다.그러나 실제 상황에서는 사용하지 마십시오!

당신 의 -i옵션 외에도sedtee 유틸리티를 .

에서 man :

티-표준 입력에서 읽고 표준 출력 및 파일에 쓰기

따라서 해결책은 다음과 같습니다.

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

-여기서는 tee파이프 라인이 버퍼링되도록하기 위해 반복됩니다. 그런 다음 파이프 라인의 모든 명령이 입력을받을 때까지 차단됩니다. 파이프 라인의 각 명령은 업스트림 명령이 1 바이트의 버퍼를 쓰면 시작됩니다 (크기는 어딘가에 정의 됨) 의 입력에 )를 . 마지막 명령tee index.html 쓰기 위해 파일을 열어서 비우는 은 업스트림 파이프 라인이 완료되고 파이프 라인 내의 버퍼에 출력 된 후에 실행됩니다.

다음이 작동하지 않을 가능성이 높습니다.

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

-차단없이 파이프 라인의 두 명령을 동시에 실행합니다. (파이프 라인을 차단하지 않고 버퍼에 의해 대신 버퍼의 라인으로 바이트 라인을 통과해야한다. 실행할 때와 동일합니다 cat | sed s/bar/GGG/. 더 상호 작용 그리고 바로이 명령 일반적으로 파이프 라인 버퍼링 및 차단없이 실행을 중단하지 않고. 긴 파이프 라인 버퍼링하십시오.) tee index.html의 뜻을 쓰기 위해 파일을 열면 비워집니다. 그러나 버퍼링을 항상 켜면 두 번째 버전도 작동합니다.


3
tee의 출력 파일도 즉시 열리고 전체 명령에 대해 빈 index.html이 생성됩니다.
sjngm

3
파이프 라인 버퍼 보다 큰 입력 파일 (보통 64KB) 이 손상 됩니다 . (@sjngm : 파일은에서와 같이 즉시 잘리지 >않지만 데이터가 손실 될 수있는 깨진 솔루션이라는 것이 핵심입니다.)
mklement0

4

명령 문제

sed 'code' file > file

그게 file 실제로 나오지를 처리하기 위해 도착하기 전에 쉘에 의해 잘립니다. 결과적으로 빈 파일이 생깁니다.

이 작업을 수행하는 sed 방법 -i은 다른 답변이 제안한대로 편집하는 데 사용 하는 것입니다. 그러나 이것이 항상 원하는 것은 아닙니다. -i원래 파일을 바꾸는 데 사용될 임시 파일을 만듭니다. 원본 파일이 링크 인 경우 문제가됩니다 (링크는 일반 파일로 대체 됨). 링크를 보존해야하는 경우 다음과 같이 임시 변수를 사용하여 sed의 출력을 파일에 다시 쓰기 전에 저장할 수 있습니다.

tmp=$(sed 'code' file); echo -n "$tmp" > file

더 나은 아직, 사용 printf대신 echo보낸 echo프로세스에 가능성 \\으로 \일부 쉘 (예를 들면 대시)에서 :

tmp=$(sed 'code' file); printf "%s" "$tmp" > file

1
링크 보존을 위해 +1 또한 임시 파일과 함께 작동합니다.sed 'code' file > file.tmp; cat file.tmp > file; rm file.tmp
dashohoxha

3

그리고 ed대답 :

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

codaddict가 응답 한 내용을 반복하기 위해 쉘은 먼저 "input.html"파일을 지우고 리디렉션을 처리 한 다음 "sed"명령을 호출하여 이제 빈 파일을 전달합니다.


2
빠른 질문, 왜 사람들이 " ed버전"의 sed답변을 계속 제공 합니까? 더 빨리 수행합니까?
cregox

6
일부 sed는 내부 -i편집을 구현하지 않습니다 . ed유비쿼터스이며 편집 내용을 원본 파일에 저장할 수 있습니다. 또한 항상 키트에 많은 도구가있는 것이 좋습니다.
glenn jackman

그래요 좋아요. 따라서 성능면에서는 제가 생각한 것과 같습니다. 감사!
cregox

2

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  1. % 모든 줄을 선택하십시오

  2. x 저장하고 닫습니다


0

선 범위를 정의하고 답을 찾을 수있는 옵션을 찾고있었습니다. 예를 들어 36-57 행에서 host1을 host2로 변경하고 싶습니다.

sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt

문자 옵션을 무시하기 위해 gi 옵션을 사용할 수도 있습니다.

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt

0

위의 정답과 관련하여 항상 스크립트를 "드라 이런 (dry run)"하는 것이 좋습니다. 따라서 파일을 손상시키지 않고 처음부터 다시 시작해야합니다.

스크립트가 출력을 파일에 쓰지 않고 명령 행에 엎 지르도록하십시오 (예 : 다음과 같이).

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

또는

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g 

이 방법으로 파일을 자르지 않고도 명령의 출력을보고 확인할 수 있습니다.

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