OSXに移植しようとしているmakefile(Linuxでgmake用に開発された)がありますが、sedは協力したくないようです。私がしていることは、GCCを使用して依存関係ファイルを自動生成し、sedを使用してそれらを少し調整することです。メイクファイルの関連部分:
$(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ではこれは問題なく実行されますが、OSXでビルドしようとすると次のようなエラーが表示されます。
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 X sed
は、-i
引数を Linux バージョンとは異なる方法で処理します。
このように-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
の後の次のものを、インプレース編集のbackup copyのファイル拡張子として解釈します。 (Linuxバージョンは、-i
と拡張子の間にスペースがない場合にのみこれを行います。)明らかに、これを使用することの副作用は、拡張子として-e
を含むバックアップファイルを取得することです。 。詳細と、代わりに使用できるよりクリーンなアプローチについては、この質問に対する他の回答を参照してください。
表示される動作は、OS X sed
がs|||
を拡張子(!)として消費し、next引数をコマンドとして解釈するためです。この場合は、 t
。これは、sed
が引数としてターゲットラベルを予期するブランチからラベルへのコマンドとして認識するため、エラーが表示されます。
ファイルtest
を作成すると、エラーを再現できます。
$ sed -i 's|x|y|' test
sed: 1: "test": undefined label 'est'
実際に
sed -i -e "s/blah/blah/" files
oS Xで期待することも行いません。代わりに、「-e」拡張子の付いたバックアップファイルを作成します。
OSに適切なのは
sed -i "" -e "s/blah/blah/" files
現在受け入れられている答えには、2つの非常に重要な点で欠陥があります。
BSD sed(OSXバージョン)では、-e
オプションはファイル拡張子として解釈されるため、-e
拡張子。
提案されているdarwinカーネルのテストは、GNUまたはBSD sedが任意の数のシステムに存在する可能性があるため、クロスプラットフォームソリューションへの信頼できるアプローチではありません。
より信頼性の高いテストは、単に--version
オプションは、GNUバージョンのsedにのみあります。
sed --version >/dev/null 2>&1
Sedの正しいバージョンが決定されると、適切な構文でコマンドを実行できます。
-iオプションのGNU sed構文:
sed -i -- "$@"
-iオプションのBSD sed構文:
sed -i "" "$@"
最後に、クロスプラットフォーム関数ですべてをまとめて、インプレース編集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ユーザーは、別のエラーが発生したため苦情を訴えました-GNU port of sedがインストールされていたため、フルパスを指定します。
martin claytonの役立つ答え は問題の良い説明を提供します[1]、しかし、彼が述べているように、潜在的に望ましくない副作用があるソリューション。
副作用のないソリューションは次のとおりです。
警告:以下のように-i
構文問題だけを解決するだけでは十分ではないかもしれません。GNU sed
とBSD/macOS sed
(包括的な議論、 この答え を参照)。
-i
の回避策:バックアップファイル一時的にを作成し、クリーンアップします。空ではないサフィックス(バックアップファイルのファイル名拡張子)オプション引数(空の文字列ではない)を使用すると、canで-i
を使用できますBSD/macOS sed
とGNU sed
の両方で機能する方法。接尾辞を-i
オプションに直接追加する。
これを利用して、すぐにクリーンアップできるバックアップファイル一時的にを作成できます。
sed -i.bak 's/foo/bar/' file && rm file.bak
バックアップを保持したい場合は、明らかに&& rm file.bak
部分を省略してください。
mv
を使用したPOSIX準拠の回避策:singleファイルのみをインプレースで編集する場合、-i
オプションをbypassedにすると、非互換性を回避できます。
sed
スクリプトおよびその他のオプションを POSIX準拠の機能 に制限する場合、以下は完全に移植可能なソリューションです(-i
は_であることに注意してください)not POSIX準拠)。
sed 's/foo/bar' file > /tmp/file.$$ && mv /tmp/file.$$ file
このコマンドは、変更を一時ファイルに書き込むだけで、sed
コマンドが成功した場合(&&
)、元のファイルを一時ファイルに置き換えます。
mv
コマンドを追加します。警告:基本的に、これは-i
が行うことです。ただし、元のファイルの許可と拡張属性(macOS)を保持しようとする点が異なります。ただし、元のファイルがsymlinkである場合、このソリューションと-i
の両方が、symlinkを通常ファイルに置き換えます。-i
の仕組みの詳細については、 この回答 の下半分を参照してください。
[1]より詳細な説明については、 this answer of mineを参照してください。
@thecarpyが投稿したソリューションを修正しました。
sed -i
の適切なクロスプラットフォームソリューションは次のとおりです。
sedi() {
case $(uname) in
Darwin*) sedi=('-i' '') ;;
*) sedi='-i' ;;
esac
LC_ALL=C sed "${sedi[@]}" "$@"
}