HOME > 電算 > シェルスクリプトがらくた入れ
シェルスクリプトがらくた入れ
自分でコピペして使うためのメモ。基本的に dash (Bourne Shell のクローン) を使っている。bash じゃないと動かないのもある(たぶん)。
とてつもなく大きなフォントで字を確認する
dekaji() { echo "/Ryumin-Light-UniJIS-UTF8-H findfont 400 scalefont setfont 100 200 moveto (`echo $1`) show" | gv - }
重複ファイルの検索と削除 etc.
重複ファイルの検索は、さまざまな人がさまざまに工夫しているようだ。車輪の再発明になるのは承知で、自分の趣味に従い、できるだけおチープで素早く動作するシェルスクリプトを書いてみる。
次のスクリプトは、適切にソートされ改行で区切られたファイル名リストを標準入力またはファイルから受け取り、そのリスト中に隣り合った二つのファイルが同一かどうか、リストの頭から diff で調べていく。隣り合ったものしか調べないので、あらかじめソートが必要となっている。シンボリックリンクは無視する。
厳密さが要求されないような場合、そして十分にファイルサイズがばらけているような場合(写真や音楽などでサイズが全く同じファイルは珍しい)、このソートは ls -S によるサイズ順のソートで成果が期待できる。より厳密にやりたければ、md5 の値でソートしたほうがよい。それでも、md5 が等しい異なるファイルが存在する以上、これでも完璧というわけではないが……。ともかく、最終的には find で比較するので、見落しはあるにしても同一ではないファイルを見つけ出す心配はない。
findsame
#!/bin/sh findsamef () { next="" isfirst=1 cat - | while read filename do this="$next" next="$filename" if [ $isfirst -eq 1 ] then isfirst=0 continue fi if test -f "$this" -a -f "$next" -a ! -h "$this" -a ! -h "$next" && diff -q "$this" "$next" > /dev/null 2>&1 then echo $this is same as $next 1>&2 comm=`echo $* | sed -e 's/%f1/$next/g; s/%f/$this/g'` eval $comm fi done } if [ -t 0 ]; then echo | findsamef "$*" else cat - | findsamef "$*" fi
使用例
ls -S | findsame 標準入力から与えられたファイルリストを前から見ていき、同じ内容のファイルが続いていれば 標準エラーでその組を報告する。その他は何もしない。 ファイルにおさめたファイル名リストを読む場合、findsame < list.txt で。 ls -S | findsame 'rm -v "%f"' 与えられたファイルリストの中に同じファイルが並んでいるとき、先にあるものを削除する。 ここで、%f は同一ファイルのペアのうち、リストで先に出てくるほうのファイルを指す。 もし、入力ファイルリストに a, b, c の順に同じ内容のファイルが並んでいたら、a, b が削除され c が残る。 (後にあるファイルを削除すると、その次にくるファイルが比較対象を失うので、ls -Sr でファイル名リストを作り 並び順を逆にしたほうがよい。) なお、標準入力がふさがっているので rm の -i オプションは不可。 ls -S | findsame 'echo %f is same as %f1' > list.txt 報告書を list.txt に作成。%f1 は同一ファイルのペアのうち、リストで後に出てくるほうのファイルを指す。 ls -S | findsame 'rm "%f"; ln -s "%f1" "%f"' 同一ファイルのペアのうち、リストで先に出てくるほうのファイルを、後に出てくるファイルに対する シンボリック・リンクで置き換える。もし、入力ファイルリストに a, b, c という同じファイルが並んでいたら、 a->b, b->c, c という関係になる。 find FILES_OR_DIRS -type f -printf '%s\t%p\n'| sort -k 1 -n | cut -f 2 | findsame ls -S の代わりに find を使ってサイズ順のリストを作成している例。 ディレクトリを再帰的に調べるような場合、ls より便利。 (よく考えてみれば sort の -n オプションは不要) find FILES_OR_DIRS -type f -exec md5sum {} \; | sort | cut -b 35- | findsame md5sum を使って、より厳しくチェック。ls -S だと、入力するファイルリスト中、同じ内容のファイルの間に、 それらと同じサイズで内容が異なるファイルがはさまっていると見逃すので、md5sum でより厳しくチェックしている。
a=b=c で d=e の5つのファイルがある場合、findsame は a b, b c, d e という3 つの組を報告するが、 これは人間には読みにくい。そこで、これを
a b c d e
と形式で二つのグループに分けて報告したいことがある。次は sed を使ってこれを行った例。
ls -S | findsame 'echo "%f|%f1"' 2> /dev/null | sed -e ':a N s/|\([^|][^|]*\)\n\1|/|\1|/ t a P D' | sed -e 's/$/\ / s/\ /\ \ / s/|/\ /g'