GNU sed 및 BSD / OSX sed 모두에서 작업하려면 내부 편집을 위해 sed -i 명령이 필요합니다.
gmake
MacOS로 포팅하려는 메이크 파일 ( Linux 용 으로 개발 됨 )이 있지만 sed
협력하고 싶지 않은 것 같습니다 . 내가하는 일은 GCC
종속성 파일을 자동 생성하는 데 사용하고 sed
. 의 관련 부분 makefile
:
$(OBJ_DIR)/%.d: $(SRC_DIR)/%.cpp
$(CPPC) -MM -MD $< -o $@
sed -i 's|\(.*\)\.o:|$(OBJ_DIR)/\1.o $(OBJ_DIR)/\1.d $(TEST_OBJ_DIR)/\1_utest.o:|' $@
GNU / Linux에서 문제없이 실행되지만 MacOS에서 빌드하려고 할 때 다음과 같은 오류가 발생합니다.
sed: 1: "test/obj/equipmentConta ...": undefined label 'est/obj/equipmentContainer_utest.d'
sed: 1: "test/obj/dice_utest.d": undefined label 'est/obj/dice_utest.d'
sed: 1: "test/obj/color-string_u ...": undefined label 'est/obj/color-string_utest.d'
sed
캐릭터를 자르는 것처럼 보이지만 해결책이 보이지 않습니다.
OS Xsed
는 Linux 버전 -i
과는 다르게 인수를 처리합니다 .
다음 -e
과 같이 추가하여 두 가지 모두에 대해 "작동"할 수있는 명령을 생성 할 수 있습니다 .
# vv
sed -i -e 's|\(.*\)\.o:|$(OBJ_DIR)/\1.o $(OBJ_DIR)/\1.d $(TEST_OBJ_DIR)/\1_utest.o:|' $@
OS X sed -i
은 다음 항목을 내부 편집 -i
의 백업 사본 에 대한 파일 확장자로 해석합니다 . (리눅스 버전 은와-i
확장자 사이에 공백이없는 경우에만이 작업을 수행합니다 .) 분명히 이것을 사용하는 부수적 인 영향은 -e
원하지 않을 수도있는 확장자로 백업 파일을 얻을 수 있다는 것입니다 . 자세한 내용과 대신 사용할 수있는 깔끔한 접근 방식은이 질문에 대한 다른 답변을 참조하십시오.
OS X가 있기 때문에 표시되는 동작은 sed
소비하는 s|||
확장 후, 해석 등 (!) 다음 명령으로 인수 - 그 시작이 경우 t
, sed
인수로 대상 레이블을 기대 지점 - 투 - 레이블 명령으로 인식을 - 따라서 오류가 발생합니다.
파일을 생성 test
하면 오류를 재현 할 수 있습니다.
$ sed -i 's|x|y|' test
sed: 1: "test": undefined label 'est'
사실은
sed -i -e "s/blah/blah/" files
MacOS에서 기대하는 바를 수행하지도 않습니다. 대신 -e
확장자 가있는 백업 파일을 생성 합니다.
MacOS에 적합한 명령은 다음과 같습니다.
sed -i "" -e "s/blah/blah/" files
Linux에서는 -i
및 사이의 공백을 제거 ""
하십시오 ( 관련 답변 참조 ).
sed -i"" -e "s/blah/blah/" files
현재 받아 들여지는 대답은 두 가지 중요한 방식으로 결함이 있습니다.
BSD sed (OSX 버전)에서는
-e
옵션이 파일 확장자로 해석되므로 확장자가있는 백업 파일을 생성합니다-e
.제안 된대로 darwin 커널을 테스트하는 것은 GNU 또는 BSD sed가 여러 시스템에 존재할 수 있으므로 크로스 플랫폼 솔루션에 대한 신뢰할 수있는 접근 방식이 아닙니다.
훨씬 더 신뢰할 수있는 테스트는 --version
sed의 GNU 버전에서만 찾을 수 있는 옵션 을 간단히 테스트 하는 것입니다.
sed --version >/dev/null 2>&1
sed의 올바른 버전이 결정되면 적절한 구문으로 명령을 실행할 수 있습니다.
-i 옵션에 대한 GNU sed 구문 :
sed -i -- "$@"
-i 옵션에 대한 BSD sed 구문 :
sed -i "" "$@"
마지막으로 모든 것을 크로스 플랫폼 함수에 통합하여 in place edit sed 명령을 실행합니다.
sedi () {
sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@"
}
사용 예 :
sedi 's/old/new/g' 'some_file.txt'
이 솔루션은 OSX, Ubuntu, Freebsd, Cygwin, CentOS, Red Hat Enterprise 및 Msys에서 테스트되었습니다.
이것은 질문에 대한 대답은 아니지만 다음을 통해 Linux와 동등한 동작을 얻을 수 있습니다.
brew install gnu-sed
# Add to .bashrc / .zshrc
export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
(이전에는에 대한 --with-default-names
옵션이 brew install gnu-sed
있었지만 최근에 제거되었습니다)
이 문제도 발견하고 다음 해결책을 생각했습니다.
darwin=false;
case "`uname`" in
Darwin*) darwin=true ;;
esac
if $darwin; then
sedi="/usr/bin/sed -i ''"
else
sedi="sed -i"
fi
$sedi 's/foo/bar/' /home/foobar/bar
나를 위해 작동 ;-), YMMV
저는 Windows, Linux 및 OS X에서 ppl이 빌드되는 다중 OS 팀에서 일합니다. 일부 OS X 사용자는 또 다른 오류가 발생하여 불평했습니다. sed의 GNU 포트가 설치되어 있으므로 전체 경로를 지정해야했습니다.
martin clayton의 유용한 답변 은 문제에 대한 좋은 설명을 제공 하지만 [1] 라고 말했듯이 잠재적으로 원치 않는 부작용이있는 솔루션입니다.
다음은 부작용이없는 솔루션입니다 .
Caveat: Solving the -i
syntax problem alone, as below, may not be enough, because there are many other differences between GNU sed
and BSD/macOS sed
(for a comprehensive discussion, see this answer of mine).
Workaround with -i
: Create a backup file temporarily, then clean it up:
With a non-empty suffix (backup-file filename extension) option-argument (a value that is not the empty string), you can use -i
in a way that works with both BSD/macOS sed
and GNU sed
, by directly appending the suffix to the -i
option.
This can be utilized to create a backup file temporarily that you can clean up right away:
sed -i.bak 's/foo/bar/' file && rm file.bak
Obviously, if you do want to keep the backup, simply omit the && rm file.bak
part.
Workaround that is POSIX-compliant, using a temporary file and mv
:
If only a single file is to be edited in-place, the -i
option can be bypassed to avoid the incompatibility.
If you restrict your sed
script and other options to POSIX-compliant features, the following is a fully portable solution (note that -i
is not POSIX-compliant).
sed 's/foo/bar' file > /tmp/file.$$ && mv /tmp/file.$$ file
This command simply writes the modifications to a temporary file and, if the
sed
command succeeds (&&
), replaces the original file with the temporary one.- If you do want to keep the original file as a backup, add another
mv
command that renames the original first.
- If you do want to keep the original file as a backup, add another
Caveat: Fundamentally, this is what
-i
does too, except that it tries to preserve permissions and extended attributes (macOS) of the original file; however, if the original file is a symlink, both this solution and-i
will replace the symlink with a regular file.
See the bottom half of this answer of mine for details on how-i
works.
[1] For a more in-depth explanation, see this answer of mine.
I've corrected the solution posted by @thecarpy:
Here's a proper cross-platform solution for sed -i
:
sedi() {
case $(uname) in
Darwin*) sedi=('-i' '') ;;
*) sedi='-i' ;;
esac
LC_ALL=C sed "${sedi[@]}" "$@"
}
'IT Share you' 카테고리의 다른 글
변수가 초기화되지 않았을 수 있음 오류 (0) | 2020.12.09 |
---|---|
Javascript로 2 자리 연도를 얻는 방법은 무엇입니까? (0) | 2020.12.09 |
Java ArrayList-목록이 비어 있는지 확인 (0) | 2020.12.09 |
.htaccess에서 cors 활성화 (0) | 2020.12.09 |
파이썬에서 json 문자열을 객체로 역 직렬화 (0) | 2020.12.09 |