web-dev-qa-db-ja.com

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

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

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

204
klickverbot

本当に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ファイルを削除することができます。

172
kine

これは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''の間にスペースが必要です。
102
klickverbot

OSXでは、ほとんどのスクリプトはGNU sedバージョン用に作成されているため、スクリプトの問題を回避するために、常にHomebrewを介してGNU sedバージョンをインストールします。

brew install gnu-sed --with-default-names

その後、BSD sedはGNU sedに置き換えられます。

または、デフォルト名なしでインストールできますが、次のようにします。

  • Gnu-sedをインストールした後、指示に従ってPATHを変更します
  • スクリプトをチェックインして、システムに応じてgsedまたはsedを選択してください
40
Lewy

動作させる方法はありません。

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

TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file

これは両方で動作します

17
analogue

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

ismail が推奨するように、

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

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

16
Alex Dupuy

回答:いいえ.

最初に受け入れられた答えは、実際には要求されたことを行いません(コメントに記載されています)。 (file-eがディレクトリに「ランダムに」表示された理由を探しているときに、この答えを見つけました。)

MacOSとLinucesの両方でsed -iを一貫して動作させる方法は明らかにありません。

価値があるものとして、私の推奨事項は、sed(複雑な障害モードがあります)でその場で更新するのではなく、新しいファイルを生成して後で名前を変更することです。つまり、-iを避けます。

13
Steve Powell

-iオプションは POSIX Sed の一部ではありません。より移植性の高い方法は、VimをExモードで使用することです。

ex -sc '%s/alfa/bravo/|x' file
  1. %すべての行を選択

  2. s置換

  3. x保存して閉じる

8
Steven Penny

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

これにより、バックアップファイルは作成されず、引用符が付加されたファイルも作成されません。

7
nwinkler

Steve Powellの答え は非常に正確です。OSXおよびLinux(Ubuntu 12.04)のsedのMANページを参照すると、2つの「インプレース」sed使用法の非互換性が強調されますオペレーティングシステム。

JFYI、Linuxバージョンのsedを使用する場合、-iと引用符(空のファイル拡張子を示す)の間にスペースがあってはなりません。したがって、

sed Linux Man Page

#Linux
sed -i"" 

そして

sed OSX Manページ

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

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

6
Big Rich

私はこの問題に遭遇しました。唯一の簡単な解決策は、Macのsedをgnuバージョンに置き換えることでした。

brew install gnu-sed
1
vikrantt

sedスクリプトでbashインプレースを実行する必要があり、そのインプレースが.bkpファイルで生成されたくない場合、OSを検出する方法があります(たとえば、 ostype.sh )、-を使用すると、bash Shellビルトイン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""`
1
sdaau

スポンジを使用できます。スポンジは古いunixプログラムで、moreutilsパッケージ(ubuntuおよびおそらくdebianの両方、およびmacのhomebrew)に含まれています。

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

manページ から:

あらすじ

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

0
Guillermo

LinuxおよびOS Xでは次のように機能します。

sed -i' ' <expr> <file>

例えばfを含むファイルaaabbaabaの場合

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

linuxとMacの両方でaaaccaacaを生成します。引用符で囲まれた文字列スペースを含むがあり、-iと文字列の間にスペースなしがあることに注意してください。一重引用符または二重引用符の両方が機能します。

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

0
David G