次のコマンドは、2 つのファイルの内容を正しく変更しています。
sed -i 's/abc/xyz/g' xaa1 xab1
しかし、私がする必要があるのは、そのようないくつかのファイルを動的に変更することであり、ファイル名がわかりません。現在のディレクトリからすべてのファイルを読み取り、ファイルの内容を変更xa*
するコマンドを書きたいと思います。sed
次のコマンドは、2 つのファイルの内容を正しく変更しています。
sed -i 's/abc/xyz/g' xaa1 xab1
しかし、私がする必要があるのは、そのようないくつかのファイルを動的に変更することであり、ファイル名がわかりません。現在のディレクトリからすべてのファイルを読み取り、ファイルの内容を変更xa*
するコマンドを書きたいと思います。sed
一致するファイル名ごとにプロセスを開始しますが、このタイプのユースケースを対象とした find の -exec 引数について誰も言及していないことに驚いています。
find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;
または、より少ないプロセスを呼び出す xargs を使用することもできます。
find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'
または、findの代わりに+
exec バリアント;
を使用して、find がサブプロセス呼び出しごとに複数のファイルを提供できるようにします。
find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +
さらに良いことに:
for i in xa*; do
sed -i 's/asd/dfg/g' $i
done
ファイルがいくつあるかは誰にもわからず、コマンドラインの制限を簡単に破ることができるからです。
ファイルが多すぎると、次のようになります。
# grep -c aaa *
-bash: /bin/grep: Argument list too long
# for i in *; do grep -c aaa $i; done
0
... (output skipped)
#
grep と sed を一緒に使用できます。これにより、サブディレクトリを再帰的に検索できます。
Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g'
OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g'
For grep:
-r recursively searches subdirectories
-l prints file names that contain matches
For sed:
-i extension (Note: An argument needs to be provided on OS X)
これらのコマンドはsed
、MacOSXに付属しているデフォルトでは機能しません。
差出人man 1 sed
:
-i extension
Edit files in-place, saving backups with the specified
extension. If a zero-length extension is given, no backup
will be saved. It is not recommended to give a zero-length
extension when in-place editing files, as you risk corruption
or partial content in situations where disk space is exhausted, etc.
試してみました
sed -i '.bak' 's/old/new/g' logfile*
と
for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; done
どちらも正常に動作します。
@PaulRはこれをコメントとして投稿しましたが、人々はそれを回答と見なす必要があります (この回答は私のニーズに最適です)。
sed -i 's/abc/xyz/g' xa*
これは、おそらく数十のオーダーの適度な量のファイルに対して機能しますが、おそらく数百万のオーダーでは機能しません。
別のより用途の広い方法は、次を使用することfind
です。
sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')