sed
Linux でテキストを検索/置換するために次のコマンドを正常に使用しました。
sed -i 's/old_link/new_link/g' *
しかし、Mac OS X で試してみると、次のようになります:
「コマンド c は \ の後にテキストが続くことを期待します」
私の Mac では通常の BASH シェルが実行されると思っていました。どうなっているのでしょうか?
編集:
@High Performance によると、これは Mac が異なる (BSD) フレーバーであるためですsed
。したがって、私の質問は、このコマンドを BSD で複製するにはどうすればよいかということですsed
。
編集:
これを引き起こす実際の例を以下に示します。
sed -i 's/hello/gbye/g' *
ベストアンサー1
オプション-i
(または--in-place
) は、変更を新しい場所にストリーミングするのではなく、ファイルをその場で編集することを意味します。
ファイルをその場で変更する場合は、バックアップ ファイルが必要であることが示唆されます。そのため、 の後にユーザー指定の拡張子が期待されます-i
が、拡張子引数の解析は GNU sed と Mac (BSD) sed では異なる方法で処理されます。
- GNU: 「拡張子が指定されていない場合、バックアップを作成せずに元のファイルが上書きされます。」 - 実質的に、ファイル拡張子の指定を完全に省略できます。拡張子は、 の直後に、間にスペースを入れずに指定する必要があります
-i
。 - Mac (BSD): 「長さがゼロの拡張子が指定された場合、バックアップは保存されません。」 -拡張子を指定する必要がありますが、必要に応じて空の文字列 '' を指定してバックアップを無効にすることもできます。
したがって、GNU と Mac では、これを異なる方法で解釈します。
sed -i 's/hello/bye/g' just_a_file.txt
- GNU : の直後に拡張子が指定されていない
-i
ため、バックアップは作成されず、s/hello/bye/g
テキスト編集コマンドとして使用され、just_a_file.txt
その場でファイルに対して処理が行われます。 - Mac (BSD) :
s/hello/bye/g
バックアップ ファイル拡張子 (!) を使用し、just_a_file.txt
テキスト編集コマンドとして使用しますが、あーあ!: そこに指定されているコマンド コードはj
(たとえば、s
置換用の有効なコマンド コードではない) なので、 でエラーが発生しますinvalid command code j
。
# This still create a `my_file.txt-e` backup on macOS Sonoma (14.5)
# and a `my_file.txt''` on Linux
sed -i'' -e 's/hello/bye/g' my_file.txt
拡張子を の直後に配置すること-i
(例:-i''
または-i'.bak'
、スペースなし) は GNUsed
では想定されていますが、macOS では の後にスペースがあること-i
(例-i ''
: または-i '.bak'
) が想定されています。
および は、以前のバージョンでは許容されていませんでしたが (たとえば、Mac OS X v10.6 では、の後に
sed
スペースが
必要でし
た。
-i
例: ) 、現在では Mac (BSD) でも受け入れられ ます。
-i '.bak'
この-e
パラメータを使用すると、編集コマンドを宣言する場所を明示的に指定できます。
2013年にMac OSがアップデートされるまでは、
ただし、GNU と Mac (BSD) 間で移植可能なコマンドは存在せず、これらのバリエーションはすべて失敗しました (エラーまたは予期しないバックアップ ファイルで)。
sed -i -e ...
-e
- Linuxでは動作しますが、バックアップを作成するためmacOSでは動作しません。sed -i '' -e ...
- macOSでは動作しますが、Linuxでは動作しませんsed -i'' -e ...
--e
macOSでバックアップファイルを作成し、''
Linuxでバックアップする
ポータブルソリューション
Linux と macOS で同じ結果を得るには、次のようないくつかのオプションがあります。
Perl を使用します:
perl -i -pe's/old_link/new_link/g' *
。gnu-sed
macOSでの使用(インストールには自家製)
# Install 'gnu-sed' on macOS using Homebrew
brew install gnu-sed
# Use 'gsed' instead of 'sed' on macOS.
gsed -i'' -e 's/hello/bye/g' my_file.txt
注:
gnu-sed
macOS では、コマンドを含むbin パスを PATH 環境変数に追加するか、 assed
のエイリアスを作成することができます(macOS をGNU に置き換えます)。 macOS 組み込みバージョンに依存するスクリプトが存在する可能性があるため、これを行わないことをお勧めします。gsed
sed
sed
sed
sed
スクリプトで を使用している場合は、次の切り替えを自動化することができますgsed
。
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "$OSTYPE" == "darwin"* ]]; then
# Require gnu-sed.
if ! [ -x "$(command -v gsed)" ]; then
echo "Error: 'gsed' is not istalled." >&2
echo "If you are using Homebrew, install with 'brew install gnu-sed'." >&2
exit 1
fi
SED_CMD=gsed
else
SED_CMD=sed
fi
# Use '${SED_CMD}' instead of 'sed'
${SED_CMD} -i'' -e 's/hello/bye/g' my_file.txt
-i ''
macOSとBSDで使用するか、-i
それ以外の場合は(GNU sed)を使用する
#!/usr/bin/env bash
set -Eeuo pipefail
case "$OSTYPE" in
darwin*|bsd*)
echo "Using BSD sed style"
sed_no_backup=( -i '' )
;;
*)
echo "Using GNU sed style"
sed_no_backup=( -i )
;;
esac
sed "${sed_no_backup[@]}" -e 's/hello/bye/g' my_file.txt