
내 프로젝트에 다음과 같은 파일의 기존 텍스트 일부를 교체해야 한다는 요구 사항이 있습니다.foo
다음과 같은 다른 텍스트로fooofoo
:
abc.txt
name
foo
foo1
그래서 나는 다음을 시도했습니다.
sed -i "s/foo/fooofoo/g" abc.txt
그러나 다음 오류가 발생합니다.
sed: 잘못된 옵션 --
i
매뉴얼에서 다음을 사용해야 한다는 것을 알았습니다.
sed -i\ "s/foo/fooofoo/g" abc.txt
그러나 이것도 작동하지 않습니다.
perl
나는 및 또한 에서 대안을 찾았 awk
지만 Solaris의 솔루션은 sed
매우 감사하겠습니다.
나는 이 버전의 bash를 사용하고 있습니다:
GNU bash, 버전 3.2.57(1)-릴리스(sparc-sun-solaris2.10)
답변1
사용ed
. 대부분의 플랫폼에서 사용할 수 있으며 파일을 그 자리에서 편집할 수 있습니다. 패턴을 바꾸는 구문을 기반으로 하기
때문에 다음과 같습니다.sed
ed
ed -s infile <<\IN
,s/old/new/g
w
q
IN
답변2
GNU sed를 설치할 수 없으면 다음을 사용하십시오.
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
이는 다음을 사용합니다.리디렉션sed의 출력을 임시 파일로 보냅니다. sed가 성공적으로 완료되면 abc.txt
임시 파일로 덮어씁니다.
GNU sed의 소스 코드에서 볼 수 있듯이, 이것이 바로 그 일 sed -i
입니다. 따라서 이것은 와 거의 비슷합니다 sed -i
.
이미 존재하는 가능성이 있는 경우 유사한 유틸리티를 사용하여 임시에 대한 고유 이름을 생성 abc.tmp
할 수 있습니다 .mktemp
답변3
와 동등한 것을 원한다면 sed -i.bak
매우 간단합니다.
GNU sed에 대해 다음 스크립트를 고려하십시오.
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
표시된 줄을 간단히 다음과 같이 바꿀 수 있습니다.
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
기존 파일을 백업으로 이동하고 새 파일을 씁니다.
우리가 동등한 것을 원한다면
sed -i -e "$script" "$dir" # no backup
그러면 조금 더 복잡해집니다. 표준 입력으로 읽기 위해 파일을 연 다음 링크를 해제한 후 sed의 출력을 대체하도록 지시할 수 있습니다.
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
이 작업을 하위 셸에서 수행하므로 이후에도 원래 표준 입력을 계속 사용할 수 있습니다. 서브쉘 없이 입력을 전환하고 다시 전환하는 것이 가능하지만 나에게는 이 방법이 더 명확해 보입니다.
새 파일을 생성하는 것보다 먼저 복사하는 데 주의를 기울이십시오 foo
. 이는 파일이 두 개 이상의 이름으로 알려지고(예: 하드 링크가 있는 경우) 링크가 깨지지 않도록 하려는 경우 중요합니다. .
답변4
사용 sed
및 없음보이는임시 파일:
별도의 생성을 피할 수 있습니다.보이는"임시 파일":
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
설명
Unix 계열 시스템은 실제로 파일 내용이 삭제될 때까지 디스크에서 파일 내용을 제거하지 않습니다.둘 다파일 시스템에서 연결이 해제되었습니다.그리고어떤 프로세스에서도 열리지 않습니다. 따라서 파일 설명자 3, 파일(파일 시스템에서 링크 해제)을 exec 3<
읽기 위해 셸에서 파일을 연 다음 파일 설명자 3을 입력으로 사용하여 호출 할 수 있습니다 .rm
sed
참고로 이는매우이것과는 다르다:
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
차이점은 하나의 명령으로 수행할 때 쉘은 파일을 자르는 옵션을 사용하여 읽기와 쓰기 모두에 대해 동일한 파일을 열 뿐이라는 것입니다. 파일은 여전히 동일하므로 내용이 손실됩니다. 그러나 읽기 위해 연 다음 rm
쓰기 위해 동일한 경로 이름을 열면 실제로는 동일한 경로 이름에 새 파일이 생성됩니다(그러나 원본이 여전히 열려 있으므로 새 inode 및 디스크 위치에 있음). 콘텐츠는 아직 사용 가능합니다.
그런 다음 작업이 끝나면 이전에 열었던 파일 설명자를 닫을 수 있습니다( exec 3<&-
특수 구문이 수행하는 작업). 그러면 운영 체제가 해당 디스크 공간을 삭제(사용하지 않은 것으로 표시)할 수 있도록 원본 파일이 해제됩니다.
주의사항
이 솔루션에 대해 명심해야 할 몇 가지 사항이 있습니다.
내용을 한 번만 "이동"할 수 있습니다.가지고 다닐 수 있는쉘이 파일 설명자에서 다시 "검색"하는 방법 - 프로그램이 내용의 일부를 읽으면 다른 프로그램은 파일의 나머지 부분만 볼 수 있습니다. 그리고
sed
전체 파일을 읽습니다.쉘/스크립트/sed가 완료되기 전에 종료되면 원본 파일이 손실될 가능성이 적습니다.