Macで-iオプションを指定したsedコマンドが失敗するが、Linuxでは機能する


303

sedLinuxで次のコマンドを使用してテキストを検索/置換できました。

sed -i 's/old_link/new_link/g' *

しかし、Mac OS Xで試してみると、次のようになります。

「コマンドcは\の後にテキストが続くことを期待しています」

私のMacは通常のBASHシェルを実行していると思いました。調子はどう?

編集:

@High Performanceによると、これはMac sedが異なる(BSD)フレーバーであることが原因です。そのため、私の質問は、このコマンドをBSDでどのように複製するsedかです。

編集:

これを引き起こす実際の例を次に示します。

sed -i 's/hello/gbye/g' *

1
つまりsed、データ内の「c」がコマンドとして認識されます。変数を使用していますか?実際のコマンドと処理中のデータをより詳しく表すものを投稿してください。を実行すると、このエラーの簡単なデモを表示できますecho x | sed c
追って通知があるまで一時停止。

@Dennis、上記の単純なコマンドがこれを引き起こしますが、処理するデータはhtmlおよびcssファイルを含むWebサイト全体(すべての画像リンクを変換しています)です...
Yarin

回答:


397

この-iオプションを使用する場合は、バックアップに拡張子を提供する必要があります。

あなたが持っている場合:

File1.txt
File2.cfg

コマンド(Macの新しいバージョンとGNUで動作させるために-i''との間にスペースがないことに注意してください-e):

sed -i'.original' -e 's/old_link/new_link/g' *

次のような2つのバックアップファイルを作成します。

File1.txt.original
File2.cfg.original

すべてのケースで機能するsedコマンドの組み合わせを見つけることは不可能であるため、バックアップファイルの作成を回避するポータブルな方法はありません。

  • sed -i -e ...- -eバックアップを作成するため、OS Xでは機能しません
  • sed -i'' -e ... -OS X 10.6では機能しませんが、10.9以降では機能します
  • sed -i '' -e ... -GNUで動作していません

すべてのプラットフォームで機能するsedコマンドが存在しない場合、別のコマンドを使用して同じ結果を得ることができます。

例えば、 perl -i -pe's/old_link/new_link/g' *


4
同じ問題がありました。この解決策をありがとう。しかし、「-i」の説明を見つけるために「man sed」で試したところ、-i ''を使用してバックアップを無視することについては何もありません。これは私の最初のせいです。次に、「コマンドは\の後にテキストが必要です」というエラーが表示された場合、なぜオプション '-i'のバックアップ名を期待していると直接通知しないのですか?そのようなことは至る所で起こります:あなたはエラーを受け取りますが、エラーの理由ではなく、それについて何も説明していないマニュアルを検索します。次に、それをグーグル検索して、他の誰かが同じ問題を抱えていることを見つけます。つまり、マニュアルに例を挙げてみませんか?
lukmac 2012

または、エラーが発生したという情報のないメッセージだけでなく、エラーが存在する理由を教えてください。すべてのツールメーカーがこのコメントを読むことができる場合、これはすべてのツールメーカーへの提案です。
lukmac 2012

5
@lukmac sed可能な限り、バックアップサフィックスを指定しました。バックアップサフィックスはs/old_link/new_link/gです。その後の次の引数は編集コマンドです。コマンドはバックアップ名として解釈されたため、最初のファイル名を編集コマンドとして使用しましたが、有効ではありませんでした。
Barmar 2014年

2
これは常に問題になりますか?AppleがOSXでGNU sedの回避策/パッケージを作成できる方法はありますか?または、GNU sedのサポートができませんでしたsed -i '' -e ...か?
2016年

5
sed -i'' -emac 10.14で期待どおりに動作しないようです
MoOx

64

OS Xでは、-iを使用するときにバックアップファイルの拡張子が必要だと思います。試してください:

sed -i .bak 's/hello/gbye/g' *

GNUを使用する場合sed、拡張機能はオプションです


55

これは、sedのGNUバージョンとBSDバージョンの両方で機能します。

sed -i'' -e 's/old_link/new_link/g' *

またはバックアップあり:

sed -i'.bak' -e 's/old_link/new_link/g' *

-iオプションの後にスペースがないことに注意してください!(GNU sedに必要)


7
最初のものはOSXで動作しません(私は10.6.8でテストしました)
marcin

4
私がOS X(10.10.3)を使用している場合、最初のファイルでは-eが付いたバックアップファイルが作成されました。駄目だ。2番目のものは、UbuntuとOS Xの間で一貫して機能した唯一のものでした。ただし、バックアップファイルは必要なかったためrm、削除した直後にコマンドを実行する必要がありました。
ブレンダン

1
10.10で動作するように、最初の行をスペースで書き換える必要があります。 sed -i'' ...=>sed -i '' ...
Daniel Jomphe、2015

3
@DanielJompheしかし、このスペースを追加してもGNU sedでは機能しません
Brice

1
@marcin最初のものは、OSX 10.11.2でも動作します。唯一のことは、後で削除する必要があるバックアップファイルを作成することです。2番目のファイルは、後でファイル名を特定する必要がないため、見栄えがよくなります。
vikas027 2017

41

Macでも同じ問題があり、次の方法で解決しましたbrew

brew install gnu-sed

そしてとして使用

gsed SED_COMMAND

sedエイリアスとして設定することもできますgsed(必要な場合):

alias sed=gsed

3
なぜあなたはOhad Kravchick まったく同じ答え出したのですか?
gniourf_gniourf 2017年

1
このようにエイリアスを設定するのは良い考えではありません
SantaXL

1
エイリアスの代わりに、対応するbrewページで推奨されているように、パスに追加します:PATH = "$(brew --prefix)/ opt / gnu-sed / libexec / gnubin:$ PATH"
y.luis

24

または、Macにgsedと呼ばれるsedのGNUバージョンをインストールし、標準のLinux構文を使用してそれを使用することもできます。

そのためには、を実行gsedして、ポートを使用してインストールします(それがない場合は、http://www.macports.org/で入手してくださいsudo port install gsed。その後、実行できますsed -i 's/old_link/new_link/g' *


24
..または自作を使用する場合は、インストールgnu-sed
Sudar

1
@Sudarさん、ありがとうございます。
Andrew Swan

9

あなたのMacは確かにBASHシェルを実行しますが、これはあなたが扱っているsedの実装の問題です。Macでは、sedはBSDに由来し、一般的なLinuxボックスで見られるsedとは微妙に異なります。お勧めしますman sed


3
BSDの問題を指摘していただきありがとうございます。しかし、文盲でかなり落ち込んでいるため、コマンドをすばやく修正する必要があります。人を一目見ただけでは何も
わかり

5
@Yarin-いいえ、そして私がsedをひと目見ただけでは何もわかりません。もっと長い目で見てください。
ハイパフォーマンスマーク

21
ほとんどのSO回答は人のどこかに埋め込まれていますが、それがSOが忙しい人々の答えです
Yarin

9

Sinetrisの答えは正しいですが、私はこれをfindコマンドと一緒に使用して、変更するファイルをより具体的にします。通常、これは機能するはずです(osxでテスト済み/bin/bash):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

一般に、複雑なプロジェクトで使用sedせずに使用するfindと効率が低下します。


-execとてもいいです!最後のスラッシュが実際に必要かどうか疑問に思っています
Ye Liu

2
@YeLiu:なしでは\;私がそのようなものを試したときにシェルによって解釈されました
serv-inc

2

sedMacOS(MacOS 10.12でテスト済み)と他のOSの違いを処理する関数を作成しました。

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

使用法:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

どこ:

, デリミタです

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' パターンです

"./mysql/.env" ファイルへのパスです


1

テンプレートファイルに環境変数を適用する方法は次のとおりです(バックアップは不要です)。

1.後で置き換えるために、{{FOO}}を使用してテンプレートを作成します。

echo "Hello {{FOO}}" > foo.conf.tmpl

2. {{FOO}}をFOO変数に置き換え、新しいfoo.confファイルに出力します

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

macOS 10.12.4Ubuntu 14.04.5の両方を使用する


0

他の回答が示すように、バックアップファイルを作成せずにOS XとLinux間で移植性のあるsedを使用する方法はありません。そのため、代わりにこのRubyワンライナーを使用しました。

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

私の場合、rakeタスク(つまり、Rubyスクリプト内)から呼び出す必要があるため、次の追加レベルの引用を使用しました。

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

-1
sed -ie 's/old_link/new_link/g' *

BSDとLinuxの両方で動作します


3
これにより、Linux上にe追加された別のファイル名が作成されます
Brice

1
壊れており、削除することをお勧めします。
ソリン2016年

MacとLinuxで動作しています。このソリューションの問題は何ですか?
Islam Azab

いいえ、Mac BSD Sedでは機能しません。ファイル名に「e」が追加されたバックアップファイルが作成されます。
Jesper Grann Laursen、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.