🗜️

テキストファイルっぽいものを全て圧縮する

2021/07/29に公開

ここでは、あるディレクトリ以下のすべてのテキストファイル (っぽいもの) に対して何らかの処理を適用する方法を考えます。これは、例えば、WEB サービスで転送するファイルを予め gzip 圧縮しておくときなんかに使えると思います。

あるディレクトリ以下の全てのファイル名を列挙する

これは find(1) を使えば一発です。速度が欲しいなら fd で代替するとよいです。

$ find
css
css/style.css
img
img/bg.jpg
img/bg.webp
img/map.png
index.html
robots.txt
sitemap.xml

ファイルの中身を調べる

file(1) を利用すると、そのファイルの内容についての情報を得ることができます。

$ file index.html 
index.html: HTML document, UTF-8 Unicode text
$ file img/bg.webp
img/bg.webp: RIFF (little-endian) data, Web/P image, VP8 encoding, 728x484, Scaling: [none]x[none], YUV color, decoders should clamp

file(1) に -i のオプションを渡すと、上のような情報の代わりに mime タイプ文字列を表示してくれます。また、-b のオプションを渡すと、行頭のファイル名表示を抑制できます。

$ file -i index.html 
index.html: text/html; charset=utf-8
$ file -bi img/bg.webp
image/webp; charset=binary

それぞれのファイルの中身を調べる

for 文を利用して find(1) の出力を file(1) の引数として渡します。

$ for name in $(find); do file -i $name; done
css: inode/directory; charset=binary
css/style.css: text/plain; charset=us-ascii
img: inode/directory; charset=binary
img/bg.jpg: image/jpeg; charset=binary
img/bg.webp: image/webp; charset=binary
img/map.png: image/png; charset=binary
index.html: text/html; charset=utf-8
robots.txt: text/plain; charset=us-ascii
sitemap.xml: text/xml; charset=us-ascii

それぞれのファイルがテキストファイルか調べる

あるファイルがテキストファイルであるなら、その mime タイプは text/ から始まるはずです。grep(1) と if 文を利用してテキストファイルであろうファイル名のみを表示します。

$ for name in $(find); do if file -bi $name | grep '^text/' >/dev/null; then echo $name; fi; done
css/style.css
index.html
robots.txt
sitemap.xml

シェルスクリプトの形で書くと次のようになります。

for name in $(find)
do
	if file -bi $name | grep '^text/' >/dev/null
	then
		echo $name
	fi
done

本題: テキストファイルっぽいものを全て圧縮する

先程の echo $name の部分を圧縮処理に書き換えれば完了します。ここでは zopfli を利用して gzip 圧縮を施すことにします。

$ for name in $(find); do if file -bi $name | grep '^text/' >/dev/null; then zopfli $name; fi; done

シェルスクリプトの形で、zopfli の代わりに gzip(1) を利用して書くと次のようになります。

for name in $(find)
do
	if file -bi $name | grep '^text/' >/dev/null
	then
		gzip -c $name >$name.gz
	fi
done

おわりに

おわりです。このシェルコマンドを応用すると、さまざまな種類のファイルに対して処理を行うことができると思います。

Discussion