web-dev-qa-db-ja.com

このOSX / BSD / GNUsedの回避策が機能しないのはなぜですか

したがって、sedは、OSX/BSDバージョンかGNUバージョンか)によって動作が異なります。

OSXには

sed -i '' <pattern> <file>

一方、これはGNU sed:

sed -i <pattern> <file>

だから私はこれを持っています:

darwin=false;
case "$(uname)" in
    Darwin*) darwin=true ;;
esac

if $darwin; then
    sedi="sed -i '' "
else
    sedi="sed -i"
fi

そして、OSXでそれを呼び出そうとします

$sedi "s/VERSION =.*;/VERSION = \"${lver}\";/g" Version.Java

また、Version.Java ''という名前のバックアップファイルを作成する以外は機能します。

CLIから明示的に行うと、なぜこれが機能しないのかわかりません。

sed -i '' "s/VERSION =.*;/VERSION = \"${lver}\";/g" Version.Java

バックアップファイルを作成しなくても機能します。

何かご意見は?

3
jshort

sedi変数を展開すると、期待どおりに空の引数を作成するのではなく、''が引数としてsedに渡されます。

これを回避するための最良の方法は、sedi変数を配列にすることです。

if $darwin; then
    sedi=(sed -i '')
else
    sedi=(sed -i)
fi

そして、このように使用します:

"${sedi[@]}" "s/VERSION =.*;/VERSION = \"${lver}\";/g" Version.Java

それ以外の場合、''を実際の空の引数に変換する唯一の方法は、元の宣言でevalを使用することだと思います。

eval $sedi '"s/VERSION =.*;/VERSION = \"${lver}\";/g"' Version.Java

ただし、コマンドの残りの部分に引用符/エスケープのレイヤーを追加する必要があるため、これはやや厄介な解決策です。また、可能な場合はevalの使用を避けることは、一般的に良い(そして安全な)方法です。

更新

以下にコメントするように、関数の作成は機能します。同じトラックで、aliasがおそらく最短の方法です。

if $darwin; then
    alias sedi="sed -i ''"
else
    alias sedi="sed -i"
fi

簡単に使用する:

sedi "s/VERSION =.*;/VERSION = \"${lver}\";/g" Version.Java
1
Graeme

代わりにsedをラップするシェル関数を定義します。

case "$(uname)" in
    Darwin*) sed () { command sed -i '' "$@"; } ;;
    *)       sed () { command sed -i "$@"; } ;;
esac
1
chepner