シェルで複数ファイルに対して一括して文字列置換処理を行うコマンド
213 views
Post
Topics about Shell of OS
"$@"シェルスクリプトに渡された全ての引数を、そのシェルスクリプト内で別のコマンドに引き渡す場合は"$@"を使います。
例えば、以下のように記述します。
grep -n cat "$@" | sed "s/cat/__CAT__/g" | tee -a ~/foo.log
"$*"や$@(ダブルクォーテーションなし)を使うと、'foo bar'のようなスペースを含む引数がスペースで分割されて壊れてしまいます。
sh -c '..."$@"...' -- "$@"1つの実行コマンドしか受け付けないsudoやssh、docker runなどで、
複数コマンドの実行などの複雑な処理を行いたいときに活躍するのがsh -c '...'です。
シェルスクリプト内でsh -c '...'にすべての引数を渡したいときは、sh -c '..."$@"...' -- "$@"と記述します。
例えば、以下のように記述します。
sudo sh -c 'grep -n cat "$@" | sed "s/cat/__CAT__/g" | tee -a /var/log/foo.log' -- "$@"
検索ワードのような「固定の引数」と、複数のファイルのような「可変長の引数」が混在しているケースです。
これらをまとめてsudoやssh、docker runなどに投げたい場合は、
-cオプションの文字列内でshiftを使います。
以下は、第一引数が検索文字列、第二引数がその検索文字列を置き換える先の文字列、 第三引数以降はこの検索と置換の対象となるファイル(複数個指定可)となっている例です。
sudo sh -c 'pattern="$1"; replace="$2"; shift 2;
grep -n "$pattern" "$@" |
sed "s/$pattern/$replace/g" |
tee -a /var/log/foo.log' -- "$@"
例として、シェルでgitで管理している全ての.cファイル内にあるabcをdefに置換する一行の書き方は以下の通りです。
-zと-0により、空白や改行を含むファイル名にも対応します。このようなファイル名がない場合には、-zと-0の両方のオプションを外してOKです。-rは対象ファイルが0件ならsedを実行しません(GNUxargs)。なお、macOS/BSD系の
sedでは次のようにするらしいです。