69

gmakeMacOS に移植しようとしている(Linux 用に開発された) makefile がありますが、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キャラクターを切り落としているように見えますが、解決策がわかりません。

4

7 に答える 7

67

OS Xsed-iは、引数をLinuxバージョンとは異なる方法で処理します。

-e次のように追加することで、両方で「機能する」コマンドを生成できます。

#      vv
sed -i -e 's|\(.*\)\.o:|$(OBJ_DIR)/\1.o $(OBJ_DIR)/\1.d $(TEST_OBJ_DIR)/\1_utest.o:|' $@

OS Xsed -iは、 の後の次のものを、インプレース編集のバックアップ コピー-iのファイル拡張子として解釈します。(Linux バージョンは、拡張子と拡張子の間にスペースがない場合にのみこれを行います。)これを使用することの明らかに副次的影響は、拡張子として を含むバックアップ ファイルを取得することです。これは望ましくない場合があります。詳細については、この質問に対する他の回答と、代わりに使用できるよりクリーンなアプローチを参照してください。-i-e

表示される動作は、OS Xがsedを拡張子(!) として使用し、次の引数をコマンドとしてs|||解釈するためです。したがって、表示されるエラー。tsed

ファイルを作成するとtest、エラーを再現できます。

$ sed -i 's|x|y|' test
sed: 1: "test": undefined label 'est'
于 2010-02-23T21:41:30.530 に答える
59

実際に、やって

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
于 2010-03-10T21:06:22.527 に答える
45

現在受け入れられている回答には、2 つの非常に重要な点で欠陥があります。

  1. BSD sed (OSX 版) では、-eオプションはファイル拡張子として解釈されるため、拡張子付きのバックアップ ファイルが作成されます-e

  2. GNU または BSD sed が任意の数のシステムに存在する可能性があるため、示唆されている darwin カーネルのテストは、クロスプラットフォーム ソリューションに対する信頼できるアプローチではありません。

より信頼性の高いテストは--version、sed の GNU バージョンでのみ見られるオプションを単純にテストすることです。

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 でテストされています。

于 2016-07-26T16:22:27.483 に答える
14

これは質問に対する完全な答えではありませんが、次の方法で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たが、最近削除されました)

于 2014-12-22T02:11:38.093 に答える
2

@thecarpy によって投稿されたソリューションを修正しました。

の適切なクロスプラットフォーム ソリューションは次のsed -iとおりです。

sedi() {
  case $(uname) in
    Darwin*) sedi=('-i' '') ;;
    *) sedi='-i' ;;
  esac

  LC_ALL=C sed "${sedi[@]}" "$@"
}
于 2016-03-02T20:10:53.977 に答える