web-dev-qa-db-ja.com

sed初心者:フォルダー内のすべてのオカレンスを変更する

フォルダー(およびそのサブフォルダー)内のすべてのファイルで正規表現の検索と置換を行う必要があります。それを行うためのLinux Shellコマンドは何ですか?

たとえば、これをすべてのファイルに対して実行し、古いファイルを新しい置換テキストで上書きします。

sed 's/old text/new text/g' 
76
nickf

Sedのみを使用して実行する方法はありません。少なくともfindユーティリティを一緒に使用する必要があります。

find . -type f -exec sed -i.bak "s/foo/bar/g" {} \;

このコマンドは、変更されたファイルごとに.bakファイルを作成します。

注:

  • sedコマンドの-i引数はGNU拡張です。そのため、このコマンドをBSDのsedで実行している場合は、出力を新しいファイルにリダイレクトし、名前を変更します。
  • findユーティリティは、古いUNIXボックスの-exec引数を実装しないため、代わりに| xargsを使用する必要があります。
115
osantana

覚えやすいので、find | xargs cmdよりfind -execを使用する方が好きです。

この例では、現在のディレクトリ以下の.txtファイルで「foo」を「bar」にグローバルに置き換えます。

find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g"

ファイル名にスペースなどのファンキーな文字が含まれていない場合、-print0および-0オプションは省略できます。

36
Dennis

移植性のために、LinuxやBSDに固有のsedの機能に依存しません。代わりに、KernighanとPikeのUnixプログラミング環境に関する本のoverwriteスクリプトを使用します。

コマンドは

find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';'

そして、overwriteスクリプト(私はあちこちで使用しています)は

#!/bin/sh
# overwrite:  copy standard input to output after EOF
# (final version)

# set -x

case $# in
0|1)        echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac

file=$1; shift
new=/tmp/$$.new; old=/tmp/$$.old
trap 'rm -f $new; exit 1' 1 2 15    # clean up files

if "$@" >$new               # collect input
then
    cp $file $old   # save original file
    trap 'trap "" 1 2 15; cp $old $file     # ignore signals
          rm -f $new $old; exit 1' 1 2 15   # during restore
    cp $new $file
else
    echo "overwrite: $1 failed, $file unchanged" 1>&2
    exit 1
fi
rm -f $new $old

これは、コマンドが成功した場合にのみファイルを上書きするという考え方です。 findで有用であり、使用したくない場所でも

sed 's/old/new/g' file > file  # THIS CODE DOES NOT WORK

sedが読み取ることができる前に、シェルがファイルを切り捨てるためです。

6
Norman Ramsey

私は(ファイルをバックアップした後)提案するかもしれません:

find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';'
1
paxdiablo