Mac(BSD)とLinuxの両方で機能するsedインプレースフラグ


237

sedLinuxとMacの両方で機能するバックアップなしのtodoインプレース編集の呼び出しはありますか?sedOS Xに同梱されているBSD はを必要sed -i '' …としているようですが、GNU sedLinuxディストリビューションは通常、引用符を(バックアップ拡張子ではsed -i …なく)空の入力ファイル名として解釈し、代わりに必要です。

両方のフレーバーで機能するコマンドライン構文はありますか?したがって、両方のシステムで同じスクリプトを使用できますか?


Perlはオプションではありませんか?sedを使用する必要がありますか?
Noufal Ibrahim 2011

たぶんGNUバージョンをインストールしてそれを使ってください!topbug.ne​​t/blog/2013/04/14/…?最初に試してみます。それからまた、そのようなものも吸います。
ドミトリーミンコフスキー2014

2
@dimadima:OS Xマシンで壊れる個人用スクリプトを持っているこの質問を閲覧している他の人にとって興味深いかもしれません。しかし、私の場合は、オープンソースプロジェクトのビルドシステムに必要でした。最初にGNU sedをインストールするようにユーザーに指示すると、この演習の本来の目的が損なわれます(「あらゆる場所で機能する」方法でいくつかのファイルをパッチする)。 。
dnadlinger 14

@klickverbotええ、理にかなっています。私は最初にコメントを回答として追加してから削除しましたが、質問に対する回答ではなかったことがわかりました:)
ドミトリーミンコフスキー2014

回答:


212

本当にsed -i「簡単」な方法を使用したい場合は、次のものが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
わかっ

これはMacでは機能しましたが、ubuntu 16.04では元のファイルが0バイトに上書きされ、.bakファイルも0バイトで作成されますか?
house9 2016年

1
注目すべきことに、macOS Sierra(およびおそらく以前は、私は便利なマシンを持ってsedいません)では、位置を受け入れませんcommand呼び出されたときに引数を-i — 別のフラグで指定する必要あります-e。このように、コマンドは次のようになりますsed -i.bak -e 's/foo/bar/' filename
ELLIOTTCABLE

5
これによりバックアップが作成されますが、OPは特にインプレース編集を要求します。
マルク=アンドレ・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に伝えます-ここでもスキップできます。
ベンジャミンW.

4
-i-i''シェルの解析時は同じであることに注意してください。最初の2つの呼び出しでは、まったく同じ引数を取得するため、異なる動作をするsed ことはできません
wchargin

44

ほとんどのスクリプトはGNU sedバージョン用に記述されているため、OSXの場合、スクリプトでの問題を回避するために、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、あなたにPATHPATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
pgericson

18

以下のようNoufalイブラヒムは尋ねる、なぜあなたは、Perlを使用することはできませんか?どのMacにもPerlがあり、ベースシステムに一部のバージョンのPerlを含まないLinuxまたはBSDディストリビューションはほとんどありません。実際にPerlが不足している可能性がある唯一の環境の1つは、BusyBox(GNU / Linuxのように機能する)です。-iバックアップ拡張を指定できないことを除いて、機能します)。

イスマイルは、推奨しています

perlはどこでも利用できるので、 perl -pi -e s,foo,bar,g target.file

そして、これはほとんどの場合、sed -iGNU / LinuxとBSD / Macの間の基本的な非互換性に対処するためのスクリプト、エイリアス、またはその他の回避策よりも優れたソリューションのようです。


このソリューションが大好きです。perl2009年5月1日以降、Linux Standard Base仕様の一部です。refspecs.linuxfoundation.org
LSB_4.0.0 /

1
これは簡単に移植性のための最良のソリューションです
ecnepsnai '25 / 07/25

17

それを機能させる方法はありません。

1つの方法は、次のような一時ファイルを使用することです。

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"> some / file; 代わりに機能しません
Jason Gross

あなたはbash変数の最大サイズによって制限されるように見えますか?GBsファイルで動作するかどうかは不明です。
アナログ

3
一時ファイルを作成している場合、@ kineが以下に提案するように、バックアップファイルを作成するための拡張子(後で削除できます)を付けてみませんか?
Alex Dupuy 2014年

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

LinuxとmacOSで動作する別のバージョンを次に示しevalます。バックアップファイルを使用したり、削除したりする必要はありません。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

スティーブパウエルの答えはです。OSXとLinux(Ubuntu 12.04)のsedのMANページを参照すると、2つのオペレーティングシステム間での「インプレース」のsedの使用における非互換性が明らかになっています。

JFYI、-iとLinuxバージョンのsedを使用する引用符(空のファイル拡張子を示す)の間にはスペースを入れないでください。

sed Linux Manページ

#Linux
sed -i"" 

そして

sed OSX Manページ

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

エイリアスのコマンドとbash 'if'内の ' uname 'のOS名出力を使用して、スクリプトでこれを回避しました。OSに依存するコマンド文字列を変数に格納しようとすると、引用符を解釈するときに失敗しました。スクリプト内で定義されたエイリアスを展開/使用するには、「shopt -s expand_aliases」を使用する必要があります。shoptの使用法はここで処理されます


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

スポンジが使えます。スポンジは、古いUnixプログラムであり、moreutilsパッケージ(ubuntuとおそらくdebianの両方、およびMacの自作)にあります。

パイプからすべてのコンテンツをバッファリングし、パイプが閉じるまで待機し(おそらく入力ファイルがすでに閉じていることを意味します)、次に上書きします。

manページから:

あらすじ

sed '...'ファイル| grep '...' | スポンジファイル


3
素晴らしいアプローチ–残念ながら、sedに頼る理由は、システム以外には依存できないクライアントマシンで使用されるクロスプラットフォームヘルパースクリプトで使用するものがあるため、元の状況では実際には役立ちません。インストールされるツール。しかし、他の誰かに役立つかもしれません。
dnadlinger 2013

0

LinuxとOS Xでは次のように動作します。

sed -i' ' <expr> <file>

たとえばをf含むファイルaaabbaaba

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

aaaccaacaLinuxとMacの両方で利回り。注引用符で囲まれた文字列があるスペースを含むと、スペースなしの間で-i、文字列が。一重引用符または二重引用符はどちらも機能します。

Linuxではbash、Ubuntu 14.04.4でバージョン4.3.11を、OS X 10.11.4 El Capitan(Darwin 15.4.0)でMacバージョン3.2.57を使用しています。


1
うわー、上記の全員の話を聞いて、不可能だと言って読まなくてよかったです。これは本当にうまくいきます。ありがとう!
Personman '18年

4
Mac OSの上で私のために動作しません...ファイル名の末尾に付加スペースを持つ新しいファイルが作成されます
フレデリック・

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.