だんだん月末に記事を書くのがパターンになってきた気がする。
やりたいことはあれども、なかなか実行に移せない今日この頃。
さて、ここしばらく仕事でよくLinuxというかUbuntuを使う機会が増えてます。
大学時代にも使ったことはありましたが、あくまでGUIだけ。最近はCUIをよく使います。
というか、そっちの方が楽なことが結構あります。
ただし、ターミナルから使おうと思うと当然コマンドを知らなければ何もできやしません。
そこで調べて知ったコマンドなどを備忘録として残しておこうとおもいます。
今回は「タイムスタンプの一括変更」です。
ソフトウェアの開発を委託して、そのソースコードを受け取ったんですけど、いざビルドしてみると、なんかワーニングが出ました。(ちなみにQtです。)
warning: Clock skew detected. Your build may be incomplete.
いやビルドできてないかもしれませんとか言われましても。。。
調べてみると、どうやらビルドに使うソースかライブラリかはわかりませんが、ともかくタイムスタンプがおかしいようです。
調べてみると、なるほど翌日の夜くらいに生成されたことになってます。
なんでや。
というわけで全てのファイルのタイムスタンプを現在以前にそろえてしまえばなんとかなりそうです。
さて、タイムスタンプを変えるには「touch」コマンドがよさそうです。
さすがにファイルも数個レベルではなく結構いっぱいあるので、一括でしてしまいたいです。
一括変更のオプションをmanページをみると・・・
ないですねぇ。。。
-Rとかでできそうなもんだけど、ないんですねぇ。
というわけでやり方をさがしたら3パターンほど出てきました。(wikipediaモロ写し)
$ find . -exec touch {} \; # command 1
$ find . | xargs touch # command 2
$ find . -print0 | xargs -0 touch # command 3
要は find コマンドと touch コマンドをどう組み合わせるのか、という所のようです。
違いがわからないのでコマンドの意味を調べました。
find [option] [path…] [expression]
指定したパスから下の階層を再帰的にたどってファイルを検索する。
-exec command \;
find コマンドのアクション。検索後に command を実行する。
command の後に、パスの代わりに “{}”(波括弧)を入力することで 検索したファイルパスを command へ渡すことができる。(セミコロンの前の”\”でエスケープ文字にしている。環境によってはバックスラッシュ。)
”\;” のかわりに ”+”を使うと、検索結果をワンラインで command へ渡すことができる。
-print0
find コマンドのオプション。ファイル名をフルパスで標準出力に表示し、各ファイル名にヌル文字を付加する。このオプションを用いれば、find の出力を処理するプログラムにおいて改行文字を含んだファイル名を正しく解釈できるようになる。
touch [-acm][-r ref_file|-t time] file…
ファイルのアクセス時刻と修正時刻を変更する。特に指定がなければ現在時刻に変更する。
xargs [option] command…
標準入力を読み込んでコマンドラインを作成し、それを実行する。
-0
xargs コマンドのオプション。指定すると、入力される項目の区切りとして空白や改行ではなくNULL文字を使用する。
コマンドの意味はこういうことだそうです。
command 1 は、基本的にfindコマンドの機能を活用したもの。
ただしfindコマンドで見つけたファイル全てに対してひとつひとつ丁寧にtouchコマンドを実行するので処理が遅いんだそうです。
command 2 では処理速度を改善するために、findコマンドで見つけたファイル名をxargsコマンドを使ってワンラインでtouchコマンドに渡すようになっています。
これによりtouchコマンドを呼び出す手間が最小限になるとのこと。
ところがサブディレクトリやファイル名にスペースがあると、ワンラインでtouchコマンドに渡していることが災いして複数のファイルとして扱われてしまいます。
command 3 では更にこの問題を改善するために、findコマンドの-print0オプションとxargsコマンドの-0オプションをうまく組み合わせています。
つまりcommand 3 が最強であると。
というわけでどのくらい処理速度に違いがあるのか気になったので、65,536個(16bit個)のファイルに対して比較してみました。
ちなみに計測には time コマンドを使用しております。
time [-p] command…
指定したコマンドの実行時間を表示する。
$ time find . -exec touch {} \;
real 1m6.366s
user 0m0.472s
sys 0m19.468s
$ time find . -print0 | xargs -0 touch
real 0m0.358s
user 0m0.100s
sys 0m0.256s
うーん、1分以上と約0.3秒じゃ全然違いますねぇ。
というところまで確認した後に気づきましたが、find コマンドの -exec オプションには末尾を”\;”にするパターン以外にも”+”にするパターンもあります。(command 4とします)
ワンラインで渡すせいで、command 2 のように スペースのあるファイルをうまく処理できないのかと思いきや、試しに実験してみると正しく実行できています。
では実行時間は?
$ time find . -exec touch {} +
real 0m0.452s
user 0m0.076s
sys 0m0.300s
はやい。絶対にはやい。
確かにcommand 3 よりは遅いけど、65,536個に対して誤差0.094秒ってもうほぼ同じじゃあないですか。
なぜwikipediaではまるでそんな方法存在しなかったかのような書き方をしているのか・・・。
極論 command 3 と command 4 のどちらでもいいのでしょうが、もしかしたら実験をした環境・条件では発生しない何かしらの問題があるのかもしれません。
いろいろと調べてすっきしりましたので、本日はここまで。
◇本日のお品◇
「linux コマンド」で検索かけたらやたら目をひく表紙だったものでつい。。。
わりと基本的なことなのにわかってないこととかありそうだからこういうのでも読んでみるといいのかもしれないですね。

コメント