제자리에 sed 편집 파일


298

편집 된 내용을 새 파일로 수동으로 스트리밍 한 다음 새 파일의 이름을 원래 파일 이름으로 바꾸지 않고 단일 sed 명령 으로 파일을 편집 할 수 있는지 확인하려고합니다 . -i옵션을 사용해 보았지만 Solaris 시스템 -i이 잘못된 옵션 이라고 말했습니다 . 다른 방법이 있습니까?


7
-ignu sed의 옵션이지만 표준 sed에는 없습니다. 그러나 내용을 새 파일로 스트리밍 한 다음 파일 이름을 변경하여 원하는 파일이 아닙니다.
William Pursell

2
실제로, 그것은 내가 원하는 것입니다. 나는 단지 새 파일의 이름을 원래 이름으로 바꾸는 평범한 작업을 수행하지 않아도되기를 원합니다.
양서류

3
그런 다음 질문을 다시 작성해야합니다.
William Pursell

3
@ amphibient : 질문 제목 앞에 'Solaris'라는 단어를 붙이시겠습니까? 귀하의 질문의 가치가 상실되고 있습니다. 내 답변 아래의 의견을 참조하십시오. 감사.
Steve

1
@Steve : Solaris 전용 접두사가 아니므로 제목에서 Solaris 접두사를 다시 제거했습니다.
tripleee

답변:


475

-i옵션 은 편집 된 컨텐츠를 새 파일로 스트리밍 한 다음 장면 뒤에서 이름을 바꿉니다.

예:

sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename

맥 OS .


3
적어도 그것은 나를 위해 그것을 할 필요가 없습니다
양서류

2
그런 다음 시스템에서 GNU sed를 컴파일하려고 시도 할 수 있습니다.
choroba

3
예 :sed -i "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
Thales Ceolin

2
이것은 펄 솔루션보다 낫습니다. 어떻게 든 .swap 파일을 만들지 않습니다 .... 감사합니다!
수학

3
@maths : 그렇습니다. 그러나 어딘가 또는 더 짧은 시간?
choroba

72

sed적절한 위치에 파일을 편집 할 수없는 시스템에서는 더 나은 솔루션을 사용하는 것이 좋습니다 perl.

perl -pi -e 's/foo/bar/g' file.txt

임시 파일을 만들지 만 비어있는 적절한 접미사 / 확장자가 제공 되었기 때문에 원본 파일을 대체합니다.


14
임시 파일을 만들뿐만 아니라 하드 링크도 끊습니다 (예 : 파일의 내용을 변경하는 대신 파일을 동일한 이름의 새 파일로 바꿉니다). 이것은 때때로 원하는 동작입니다. 허용되지만 파일에 대한 여러 링크가있는 경우 거의 항상 잘못된 동작입니다.
William Pursell

3
@DwightSpencer : Perl이없는 모든 시스템이 손상되었다고 생각합니다. 높은 권한을 원하고 사용해야하는 경우 단일 명령이 일련의 명령보다 우선합니다 sudo. 내 생각에 문제는 최신 GNU 또는 BSD를 설치하지 않고 임시 파일을 수동으로 만들고 이름을 바꾸지 않는 방법에 관한 것 sed입니다. Perl을 사용하십시오.
Steve

4
@PetrPeller : 정말요? 질문을주의 깊게 읽으면 OP가 다음과 같은 것을 피하려고한다는 것을 이해할 것입니다 sed 's/foo/bar/g' file.txt > file.tmp && mv file.tmp file.txt. 전체 편집이 임시 파일을 사용하여 이름을 변경한다고 해서 옵션을 사용할 수 없을 때 수동으로 이름을 변경 해야 한다는 의미 는 아닙니다. 원하는 것을 수행 할 수있는 다른 도구가 있으며 Perl이 확실한 선택입니다. 이것이 원래 질문에 대한 답이 아닌가?
Steve

2
@a_arias : 네 말이 맞아. 그는했다. 그러나 그는 솔라리스를 사용하여 원하는 것을 달성 할 수 없습니다 sed. 이 질문은 실제로 매우 좋은 것이었지만, 맨 페이지를 읽지 못하거나 여기에 실제로 질문을 읽을 필요가없는 사람들에 의해 그 가치는 줄어 들었 습니다.
Steve

4
@EdwardGarson : IIRC, Solaris는 Perl과 함께 제공되지만 Python 또는 Ruby는 제공하지 않습니다. 이전에 말했듯이 OP는 Solaris sed를 사용하여 원하는 결과를 얻을 수 없습니다.
Steve

56

OS X에서는이 명령을 실행할 때 "유효하지 않은 명령 코드"와 같은 이상한 오류나 다른 이상한 오류가 발생할 수 있습니다. 이 문제를 해결하려면

sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>

의 OSX 버전 때문이다 sed-i옵션은 예상 extension명령이 실제로로서 해석되도록 인수 extension인수 및 파일 경로가 명령 코드로 해석됩니다. 출처 : https://stackoverflow.com/a/19457213


1
이것은 OS X의 또 다른 이상한 점입니다. 운 좋게도 의지 brew install gnu-sed와 함께 PATHsed의 GNU 버전을 사용할 수 있습니다. 언급 해 주셔서 감사합니다. 확실한 머리 긁는 도구.
Doug

23

다음은 내 Mac에서 잘 작동합니다.

sed -i.bak 's/foo/bar/g' sample

샘플 파일에서 foo를 bar로 바꿉니다. 원본 파일의 백업은 sample.bak에 저장됩니다

백업없이 인라인을 편집하려면 다음 명령을 사용하십시오.

sed -i'' 's/foo/bar/g' sample

백업 파일을 유지하지 못하게하는 방법은 무엇입니까?
Petr Peller

@PetrPeller, 당신은 같은에 대해 언급 된 명령을 사용할 수 있습니다 ... sed -i '' 's / foo / bar / g'샘플
minhas23

18

주목해야 sed할 것은 sed의 유일한 목적으로 파일을 자체적으로 작성할 수 없다는 것입니다. "스트림"의 편집기 (예 : stdin, stdout, stderr 및 기타 >&n버퍼, 소켓 등의 파이프 라인 )로 작동하는 것입니다. 이를 염두에두고 다른 명령 tee을 사용 하여 출력을 파일에 다시 쓸 수 있습니다 . 또 다른 옵션은 컨텐츠를로 파이핑하여 패치를 작성하는 것 diff입니다.

티 방법

sed '/regex/' <file> | tee <file>

패치 방법

sed '/regex/' <file> | diff -p <file> /dev/stdin | patch

최신 정보:

또한 patch는 diff 출력의 1 행에서 파일을 변경합니다.

패치는 diff의 출력 첫 줄에있는 파일 중 액세스 할 파일을 알 필요가 없습니다.

$ echo foobar | tee fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar   2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin  2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar

$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar

2
/dev/stdin 2014-03-15, 1 월 7답변 -시간 여행자입니까?
Adrian Frühwirth

Windows에서 msysgit을 사용 /dev/stdin하면 교체해야하므로, 존재하지 않는 /dev/stdin다음 명령이 작동해야하므로, 따옴표없이, 단일 하이픈 '-'로 $ sed 's/oo/u/' fubar | diff -p fubar -$ sed 's/oo/u/' fubar | diff -p fubar - | patch
짐 나전

@ AdrianFrühwirth 나는 어딘가에 파란 경찰 상자를 가지고 있으며 어떤 이유로 그들은 나를 직장에서 의사라고 부릅니다. 그러나 솔직히, 당시 시스템에 시계 드리프트가 심하게 나쁜 것 같습니다.
드와이트 스펜서

이 솔루션은 특정 버퍼링 동작에 의존합니다. sed가 읽는 동안 더 큰 파일이 깨질 수 있다고 생각합니다. 패치 명령으로 파일이 변경되기 시작하거나 파일을 자르는 tee 명령으로 인해 파일이 더 나빠질 수 있습니다. 실제로 patch잘리지 않을지 확실 하지 않습니다. 출력을 다른 파일에 저장 한 다음 cat원본에 저장하는 것이 더 안전하다고 생각합니다.
akostadinov 12

@ william-pursell
akostadinov의

11

당신이 원하는 것을 할 수는 없습니다 sed. sed해당 버전의 -i파일을 수정하는 옵션을 지원하는 버전조차도 사용자가 명시 적으로 원하지 않는 것을 정확하게 수행합니다. 임시 파일에 쓴 다음 파일 이름을 바꿉니다. 그러나 아마도 당신은 그냥 사용할 수 있습니다 ed. 예를 들어, 모든 항목 변경 foobar파일의를 file.txt, 당신은 할 수 있습니다 :

echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt

구문은와 유사 sed하지만 정확히 동일하지는 않습니다.

그러나 이름이 바뀐 임시 파일을 사용하지 않는 이유를 고려해야합니다. 당신이없는 경우에도 -i지원을 sed, 당신은 쉽게 당신을 위해 일을하는 스크립트를 작성할 수 있습니다. 대신 sed -i 's/foo/bar/g' file할 수 있습니다 inline file sed 's/foo/bar/g'. 이러한 스크립트는 작성하기가 쉽지 않습니다. 예를 들면 다음과 같습니다.

#!/bin/sh -e
IN=$1
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "$@" >$tmp && cat $tmp > $IN  # preserve hard links

대부분의 용도에 적합해야합니다.


1
예를 들어이 스크립트의 이름을 어떻게 지정하고 어떻게 호출합니까?
양서류

2
나는 그것을 부를 것이다 inline그것을 호출 위와 같이 설명 :inline inputfile sed 's/foo/bar/g'
윌리엄 Pursell

1
와우, ed실제로 제자리에있는 답변 만. 내가 처음으로 필요합니다 ed. 감사합니다. 약간의 최적화는 사용 echo -e ",s/foo/bar/g\012 w"또는 echo $',s/foo/bar/g\012 w'쉘이 추가 tr호출 을 피할 수있는 곳 입니다.
akostadinov

2
ed실제로 수정 작업을 수행하지 않습니다. 에서 strace출력, GNU는 ed, 임시 파일을 생성하는 임시 파일에 변경 내용을 기록하고 하드 링크를 보존, 전체 원본 파일을 다시 작성합니다. 에서 truss출력, 솔라리스 11은 ed또한 임시 파일을 사용하지만 함께 저장시 원본 파일 이름으로 임시 파일의 이름을 변경 w하드 링크를 파괴하는 명령.
Andrew Henle

@AndrewHenle 실망 스럽습니다. ed현재 맥 OS (모하비, 무엇이든 그 마케팅 용어 수단)와 함께 제공 여전히 하드 링크를 보존하고있다. YMMV
William Pursell

10

vi를 사용할 수 있습니다

vi -c '%s/foo/bar/g' my.txt -c 'wq'

9

sed 는 내부 편집을 지원합니다. 보낸 사람 man sed:

-i[SUFFIX], --in-place[=SUFFIX]

    edit files in place (makes backup if extension supplied)

:

hello.txt텍스트 가있는 파일이 있다고 가정 해 봅시다 .

hello world!

이전 파일의 백업을 유지하려면 다음을 사용하십시오.

sed -i.bak 's/hello/bonjour' hello.txt

다음 hello.txt과 같은 두 개의 파일로 끝납니다 .

bonjour world!

그리고 hello.txt.bak오래된 내용으로.

사본을 유지하지 않으려면 확장 매개 변수를 전달하지 마십시오.


3
OP는 특히 그의 플랫폼이 (인식이지만) 비표준 옵션을 지원하지 않는다고 언급합니다.
tripleee

3

사용중인 쉘을 지정하지 않았지만 zsh를 사용하면 =( )구성을 사용하여 이를 달성 할 수 있습니다 . 다음과 같은 내용이 있습니다.

cp =(sed ... file; sync) file

=( )는 종료 >( )될 때 자동으로 삭제되는 임시 파일을 생성하지만 비슷합니다 cp.


3
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt

출력은 원래 파일의 내용을 덮어 쓰도록 지시되고 sed의 특수 버전이 필요하지 않기 때문에 모든 하드 링크를 보존해야합니다.


3

같은 양의 문자를 바꾸고 파일의 "In-place"편집 내용을 주의 깊게 읽은 후 ...

리디렉션 연산자 <>를 사용하여 읽고 쓸 파일을 열 수도 있습니다 .

sed 's/foo/bar/g' file 1<> file

라이브보기 :

$ cat file
hello
i am here                           # see "here"
$ sed 's/here/away/' file 1<> file  # Run the `sed` command
$ cat file
hello
i am away                           # this line is changed now

에서 읽기와 쓰기에 대한 배쉬 참조 설명서 → 3.6.10 열기 파일 설명 :

리디렉션 연산자

[n]<>word

파일 디스크립터 n에서 읽기 및 쓰기를 위해 또는 n이 지정되지 않은 경우 파일 디스크립터 0에서 이름이 확장 된 단어의 파일이 열립니다. 파일이 없으면 작성됩니다.


파일에 의해 손상되었습니다. 나는 그 이유가 확실하지 않습니다. paste.fedoraproject.org/462017
Nehal J Wani

참조 라인 [43 ~ 44], [88 ~ 89], [135-136]
Nehal J 와니

2
이 블로그 포스트는 왜이 답변을 사용하지 않아야하는지 설명합니다. backreference.org/2011/01/29/
제자리 편집 파일

@NehalJWani 나는 기사를 오랫동안 읽었을 것입니다. 대답에서 언급하지 않은 것은 동일한 문자 수를 변경하면 작동한다는 것입니다.
fedorqui 'SO 중지 피해'10

@NehalJWani이 말은 내 대답이 파일에 해를 끼쳤다면 미안합니다. 제공 한 링크를 읽은 후 수정 사항으로 업데이트하거나 필요한 경우 삭제합니다.
fedorqui 'SO 중지 피해'10

2

Skyfall에서 Moneypenny가 말한 것처럼 "때로는 옛날 방식이 가장 좋습니다." Kincade는 나중에 비슷한 것을 말했습니다.

$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}

적절한 편집. 파일 쓰기를 위해 '\ nw \ n'을 추가했습니다. 지연 응답 요청에 대한 사과드립니다.


이것이 무엇을 설명 할 수 있습니까?
Matt Montag

1
stdin에 쓴 문자가있는 텍스트 편집기 인 ed (1)를 호출합니다. 30 세 미만의 사람으로서, 공룡이 우리에게 ed (1)이 공룡에 해당한다고 말하는 것이 좋습니다. 어쨌든 ed를 열고 입력하는 대신 jlettvin은 사용중인 캐릭터를 파이핑하고 |있습니다. @MattMontag
Ari Sweedler

명령이 수행하는 작업을 요청하는 경우 명령으로 끝나는 두 가지가 있습니다 \n. [range] s / <old> / <new> / <flag>는 대체 명령의 형태입니다. 다른 텍스트 편집기에서도 여전히 볼 수있는 패러다임 (좋아요, vim, ed의 직계 자손) 어쨌든 g깃발은 "글로벌"이며 "보이는 각 줄의 모든 인스턴스"를 의미합니다. 범위 3,5는 3-5 행을 봅니다. ,5StartOfFile-5, 3,3-EndOfFile 행 및 ,StartOfFile-EndOfFile을 봅니다. "false"를 "true"로 바꾸는 모든 줄의 전역 대체 명령입니다. 그런 다음 쓰기 명령을 w입력합니다.
Ari Sweedler

1

아주 좋은 예입니다. 많은 파일을 편집하는 데 어려움이 있었고 -i 옵션은 find 명령 내에서 파일을 사용하는 유일한 합리적인 솔루션 인 것 같습니다. 각 파일의 첫 줄 앞에 "version :"을 추가하는 스크립트는 다음과 같습니다.

find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.