Mac (BSD) 및 Linux 모두에서 작동하는 sed 위치 내 플래그


237

sedLinux와 Mac 모두에서 작동하는 백업없이 Todo in-place 편집을 호출 합니까? sedOS X와 ​​함께 제공 되는 BSD 는 필요할 것 같지만 sed -i '' …, GNU sedLinux 배포판은 일반적으로 따옴표를 백업 확장자 대신 빈 입력 파일 이름으로 해석하여 대신 필요로 sed -i …합니다.

두 가지 특징 모두에서 작동하는 명령 줄 구문이 있습니까? 두 시스템에서 동일한 스크립트를 사용할 수 있습니까?


펄은 옵션이 아닌가? 반드시 당신은 나오지도 사용할 수 있습니까?
Noufal Ibrahim

아마도 GNU 버전을 설치하고 사용하십시오! topbug.net/blog/2013/04/14/… ? 나는 그것을 먼저 시도 할 것입니다. 다시, 그런 종류의 짜증도.
Dmitry Minkovsky

2
@ dimadima : OS X 컴퓨터에서 개인 스크립트가있는이 질문을 탐색하는 다른 사람들에게는 흥미로울 수 있습니다. 제 경우에는 오픈 소스 프로젝트의 빌드 시스템에 필요했습니다. 사용자에게 GNU sed를 먼저 설치하라고 지시하면이 연습의 원래 목적을 잃어 버렸을 것입니다. .
dnadlinger

@klickverbot 예, 이해합니다. 먼저 주석을 답변으로 추가 한 다음 삭제하여 귀하의 질문에 대한 답변이 아니라는 것을 깨달았습니다. :).
Dmitry Minkovsky 2014 년

1
상호 참조 : sed -i (in-place editing)로 이식성을 얻는 방법은 무엇입니까? 유닉스 및 리눅스 스택 교환에서.
MvG

답변:


212

실제로 sed -i'쉬운'방법을 사용하려면 다음 DOES가 GNU와 BSD / Mac 모두에서 작동합니다 sed.

sed -i.bak 's/foo/bar/' filename

공간 부족과 점에 유의하십시오.

증명:

# GNU sed
% sed --version | head -1
GNU sed version 4.2.1
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file  file.bak
% cat ./file
bar

# BSD sed
% sed --version 2>&1 | head -1
sed: illegal option -- -
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file  file.bak
% cat ./file
bar

분명히 .bak파일을 삭제할 수 있습니다.


2
이것은 갈 길입니다. 몇 개의 문자를 추가하면 휴대 할 수 있습니다. 백업 파일을 삭제하는 것은 간단합니다 (호출 할 때 파일 이름이 이미 있습니다 sed)
slezica

이것은 Mac에서 작동했지만 우분투 16.04에서는 원본 파일을 0 바이트로 덮어 쓰고 0 바이트로 .bak 파일을 만듭니다.
house9

1
참고로, 맥 OS 시에라에, (그리고 아마도 이전, 나는 기계 편리한이없는) sed의 위치에 동의하지 않는 command호출 할 때 인수를 -i-이 있어야 다른 플래그와 공급, -e. 따라서 명령은 다음과 같습니다.sed -i.bak -e 's/foo/bar/' filename
ELLIOTTCABLE

5
OP는 특히 내부 편집을 요청하는 동안 백업을 생성합니다.
Marc-André Lafortune

8
전체 솔루션은 다음과 같습니다.sed -i.bak 's/foo/bar/' file && rm file.bak
joeytwiddle

112

이것은 GNU sed에서는 작동하지만 OS X에서는 작동하지 않습니다.

sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file

이것은 OS X에서는 작동하지만 GNU sed에서는 작동하지 않습니다.

sed -i '' -e 's/foo/bar/' target.file

OS X에서는

  • sed -i -e백업 파일의 확장자가로 설정되어 있기 때문에 사용할 수 없습니다-e
  • sed -i'' -e같은 이유로 사용할 수 없습니다 – -i와 사이에 공백이 필요합니다 ''.

1
@AlexanderMills sed는 다음 인수가 명령임을 알려줍니다. 여기서 건너 뛸 수도 있습니다.
Benjamin W.

4
참고 그 -i-i''쉘 구문 분석시 동일하다; 정확히 동일한 인수를 얻으므로 두 번의 첫 호출에서 다르게 작동 sed 할 수 없습니다 .
wchargin 2016 년

44

OSX에서는 대부분의 스크립트가 GNU sed 버전 용으로 작성 되었기 때문에 스크립트의 문제를 피하기 위해 항상 Homebrew를 통해 GNU sed 버전을 설치합니다.

brew install gnu-sed --with-default-names

그러면 BSD sed가 GNU sed로 대체됩니다.

또는 기본 이름없이 설치할 수 있지만 다음을 수행하십시오.

  • PATH설치 후 지시에 따라 변경gnu-sed
  • 시스템에서 gsed또는 sed시스템에 따라 스크립트를 체크인하십시오

4
--with-default-names사제 코어에서 제거 에 대한 추가 정보를 원하시면 대답. gnu-sed지금 설치할 때 설치 지침에 다음을 추가해야한다고 지정 gnubin합니다 PATH.PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
pgericson

18

Noufal Ibrahim이 묻는 것처럼 Perl을 사용할 수없는 이유는 무엇입니까? 모든 Mac에는 Perl이 있으며 기본 시스템에 일부 Perl 버전을 포함하지 않는 Linux 또는 BSD 배포판은 거의 없습니다. 실제로 Perl이 없을 수있는 유일한 환경 중 하나는 BusyBox입니다 ( -i백업 확장명을 지정할 수 없다는 점을 제외하고 GNU / Linux 용으로 작동 ).

ismail이 권장하는 대로

펄은 어디에서나 사용할 수 있기 때문에 perl -pi -e s,foo,bar,g target.file

이것은 sed -iGNU / Linux와 BSD / Mac 의 기본적인 비 호환성을 처리하기 위해 스크립트, 별명 또는 기타 해결 방법보다 거의 모든 경우에 더 나은 솔루션 인 것 같습니다 .



1
이것은 이식성을위한 최고의 솔루션입니다
ecnepsnai

17

작동시킬 방법이 없습니다.

한 가지 방법은 다음과 같은 임시 파일을 사용하는 것입니다.

TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file

이것은 둘 다에서 작동합니다


SOME_FILE = "$ (sed -s"s / abc / def / "some / file)"; echo "$ SOME_FILE"> 일부 / 파일; 대신 작동하지 않습니다
Jason Gross

bash 변수의 최대 크기에 의해 제한되는 것처럼 보입니다. GB 파일에서 작동하는지 확실하지 않습니다.
아날로그

3
임시 파일을 작성하는 경우 @kine이 제안하는 것처럼 백업 파일을 작성하고 (제거 할 수있는) 확장명을 지정하는 것이 어떻습니까?
Alex Dupuy

13

답 : 아니요.

원래 승인 된 답변은 실제로 요청에 따라 수행되지 않습니다 (의견에 명시된 바와 같이). (a file-e가 내 디렉토리에 "무작위로"나타나는 이유를 찾을 때이 답변을 찾았습니다 .

sed -iMacOS와 Linuces에서 일관되게 작업 할 수있는 방법은 없습니다 .

가치있는 것에 대한 나의 추천 sed은 (복잡한 실패 모드를 가진) 제자리로 업데이트 하는 것이 아니라 새 파일을 생성하고 나중에 이름을 바꾸는 것입니다. 즉, 피하십시오 -i.


9

-i옵션은 POSIX Sed의 일부가 아닙니다 . 보다 편리한 방법은 Ex 모드에서 Vim을 사용하는 것입니다.

ex -sc '%s/alfa/bravo/|x' file
  1. % 모든 줄을 선택하십시오

  2. s 바꾸다

  3. x 저장하고 닫습니다


이것이 정답입니다. POSIX의 주요 기능은 이식성입니다.
Kajukenbo

9

eval백업 파일을 사용 하거나 삭제하지 않고 Linux 및 macOS에서 작동하는 다른 버전이 있습니다. sed매개 변수 를 저장하기 위해 Bash 배열을 사용합니다 eval.

# Default case for Linux sed, just use "-i"
sedi=(-i)
case "$(uname)" in
  # For macOS, use two parameters
  Darwin*) sedi=(-i "")
esac

# Expand the parameters in the actual call to "sed"
sed "${sedi[@]}" -e 's/foo/bar/' target.file

이렇게하면 백업 파일이 생성되지 않으며 따옴표가 추가 된 파일도 생성되지 않습니다.


2
이것이 정답입니다. 나는 조금 단순화하지만 아이디어는 완벽하게 작동합니다 sedi=(-i) && [ "$(uname)" == "Darwin" ] && sedi=(-i '') sed "${sedi[@]}" -e 's/foo/bar/' target.file
Alex Skrypnyk

좋은 물건! 그래도 가독성을 위해 더 긴 버전을 선호합니다.
nwinkler

1
이것은 다른 시스템과 호환되는 가장 좋은 방법입니다.
Victor Choy

6

Steve Powell의 대답 은 매우 정확합니다 .OSX 및 Linux에서 sed에 대한 MAN 페이지를 참조하면 (Ubuntu 12.04) 두 운영 체제에서 'in-place'sed 사용법의 비 호환성을 강조합니다.

JFYI, -i와 sed의 Linux 버전을 사용하는 따옴표 (빈 파일 확장자를 나타냄) 사이에는 공백이 없어야합니다.

sed Linux 매뉴얼 페이지

#Linux
sed -i"" 

sed OSX 매뉴얼 페이지

#OSX (notice the space after the '-i' argument)
sed -i "" 

별칭 'd 명령과 bash'if '내에서 ' uname ' 의 OS 이름 출력을 사용하여 스크립트 에서이 문제를 해결했습니다 . 따옴표를 해석 할 때 OS 종속 명령 문자열을 변수에 저장하려는 시도가 발생했습니다. 스크립트 내에 정의 된 별칭을 확장 / 사용하려면 ' shopt -s expand_aliases '를 사용해야합니다. shopt의 사용법은 here 처리 됩니다 .


1

스크립트 sed에서 내부 작업을 수행해야하고 내부에서 bash.bkp 파일을 생성하지 않으려는 경우 os를 감지 할 수있는 방법이 있습니다 (예 : ostype.sh 사용 ). bash셸이 내장 된 다음 해킹 eval이 작동합니다.

OSTYPE="$(bash ostype.sh)"

cat > myfile.txt <<"EOF"
1111
2222
EOF

if [ "$OSTYPE" == "osx" ]; then
  ISED='-i ""'
else # $OSTYPE == linux64
  ISED='-i""'
fi

eval sed $ISED 's/2222/bbbb/g' myfile.txt
ls 
# GNU and OSX: still only myfile.txt there

cat myfile.txt
# GNU and OSX: both print:
# 1111
# bbbb

# NOTE: 
# if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
# then you will get a backup file with quotations in the file name, 
# - that is, `myfile.txt""`

0

스폰지를 사용할 수 있습니다. Sponge는 moreutils 패키지 (우분투와 데비안, Mac의 홈브류)에있는 오래된 유닉스 프로그램입니다.

파이프의 모든 내용을 버퍼링하고 파이프가 닫힐 때까지 기다린 후 (입력 파일이 이미 닫 혔음을 의미 함) 덮어 씁니다.

로부터 man 페이지 :

개요

sed '...'파일 | grep '...'| 스폰지 파일


3
좋은 접근 방식 – 불행히도 sed에 의존하는 이유는 클라이언트 시스템에서 사용되는 크로스 플랫폼 헬퍼 스크립트에서 사용할 것이기 때문에 원래 상황에서 실제로 도움이되지 않습니다. 설치되는 도구. 그래도 다른 사람에게 도움이 될 수 있습니다.
dnadlinger

0

다음은 Linux 및 OS X에서 작동합니다.

sed -i' ' <expr> <file>

예를 f들어aaabbaaba

sed -i' ' 's/b/c/g' f

aaaccaaca리눅스와 맥 모두에서 생산량 . 공백 과 문자열 사이에 공백없는 인용 문자열 있습니다. 작은 따옴표 또는 큰 따옴표는 모두 작동합니다.-i

Linux에서는 bashUbuntu 14.04.4에서 4.3.11 버전을 사용 하고 OS X 10.11.4 El Capitan (Darwin 15.4.0)에서 Mac 버전 3.2.57을 사용하고 있습니다.


1
와, 나는 불가능하다고 말하고 계속 읽는다는 말을 듣지 않아서 기쁘다! 이것은 실제로 작동합니다. 감사!
Personman

4
Mac OS에서 작동하지 않습니다 ... 파일 이름 끝에 공백이 추가 된 새 파일이 생성됩니다.
Frédéric

Mac에서 나에게도 작동하지 않습니다 (/ usr / bin / sed)-이제 파일 이름에 공백이 추가 된 추가 백업 파일이 있습니다 :-(
paul_h

작은 따옴표에서 공백을 제거해보십시오.
dps

0

나는이 문제에 부딪쳤다. 유일한 빠른 해결책은 Mac에서 sed를 gnu 버전으로 바꾸는 것입니다.

brew install gnu-sed

이것은 기존 답변을 2015 년부터 훨씬 더 자세하게 복제 한 것입니다.
tripleee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.