sedにドライランオプションはないけど、ファイルを変更せずにdiffが見たい。
sed command in dry run - Stack Overflowにコマンドを組み合わせて、diffを見るやり方が書いてあった。
例えば
editor.txt
Vim
Emacs
Atom
Visual Studio Code
こんなファイルがあった場合に
$ sed 's/Emacs/Vim/g' editor.txt | diff editor.txt -
--- editor.txt 2017-05-07 12:47:25.000000000 +0900
+++ - 2017-05-07 12:47:59.390599000 +0900
@@ -1,4 +1,4 @@
Vim
-Emacs
+Vim
Atom
Visual Studio Code
な感じでdiffが見れる。
これをシェルスクリプト化してみた。
sedd
#!/usr/bin/env bash
progname=$(basename $0)
usage() {
cat <<EOT
Usage: $progname [OPTIONS]
Options:
-h, --help
-n, --dry-run
EOT
}
for OPT in "$@"
do
case "$OPT" in
'-h'|'--help' )
usage
;;
'-n'|'--dry-run' )
dryrun=1
shift 1
;;
*)
param+=( $(printf %q "$1") )
shift 1
;;
esac
done
if [ -z "$param" ]; then
usage
exit 1
fi
if [ "$dryrun" ]; then
cmd="sed ${param[@]} {} | diff -u {} -"
exec find . -type f -exec sh -c "$cmd" \;
fi
eval "find . -type f -exec sed -i ${param[@]} {} +"
-n
か--dry-run
をつけるとドライラン
$ sedd 's/Emacs/Vim/' -n
--- ./editor.txt 2017-05-07 12:47:25.000000000 +0900
+++ - 2017-05-07 12:55:16.585676000 +0900
@@ -1,4 +1,4 @@
Vim
-Emacs
+Vim
Atom
Visual Studio Code
つけないと実行される。-e
で複数指定してもうまくいく。
$ sedd -e 's/Emacs/Vim/' -e 's/Atom/Vim/' -n
--- ./editor.txt 2017-05-07 12:47:25.000000000 +0900
+++ - 2017-05-07 13:10:30.560533000 +0900
@@ -1,4 +1,4 @@
Vim
-Emacs
-Atom
+Vim
+Vim
Visual Studio Code
対象はカレントワーキングディレクトリ以下のファイル全体にしている。
オプション解析のところで、param+=( $(printf %q "$1") )
しているのは
$ sedd 's/Visual Studio Code/Vim/' -n
のように引数に空白などのエスケープが必要な文字が来ても、後のsed実行時に問題なく動かすため。
$ printf %q 's/Visual Studio Code/Vim'
s/Visual\ Studio\ Code/Vim
な感じに変換される。printf %q
についてはBashで文字列をエスケープをする - Qiitaで知った。
最後のfindの+は、-execで対象ファイルを並べるオプション
sed -i ${param[@]} file1 file2 ...
みたいな感じになり、1個ずつファイルをsedするよりも早くなる。