WindowsのROBOCOPYコマンドでタイムスタンプを維持したままコピーする
はじめに
ペルソナQをDL販売で買おうと思ったらSDカードの容量が足りないじゃん!
というわけで、容量の大きいものに交換することにしました。コピー自体は普通にSDカード内のフォルダごとコピーしてやればいいようです。
パソコンを使ってデータを移動する場合は、「Nintendo 3DS」フォルダをコピーすることによって、元のSDカードに保存されていたダウンロードソフトやゲームのセーブデータを新しいSDカードに引き継ぐことができます。 ニンテンドー3DS|Q&A|Nintendo http://www.nintendo.co.jp/3ds/support/qa/
…が、この場合ファイルのタイムスタンプが更新されてしまうので、写真などが保存されている場合は日時が変わってしまう様子。
Windowsの場合はFire File Copy等のツールを使ってタイムスタンプを維持したままコピーすることが多いようですが、ちょっと調べてみると標準*1のROBOCOPYコマンドを使用すればできそうだったので、やってみました。
環境
ROBOCOPYコマンド
ROBOCOPYコマンドのヘルプを見てみると、こんなことが書いてあります。
C:\> ROBOCOPY /? ------------------------------------------------------------------------------- ROBOCOPY :: Windows の堅牢性の高いファイル コピー ------------------------------------------------------------------------------- 開始: 2014年6月6日 3:39:31 使用法:: ROBOCOPY コピー元 コピー先 [ファイル [ファイル]...] [オプション] コピー元 :: コピー元ディレクトリ (ドライブ:\パスまたは \\サーバー\共有\パス)。 コピー先 :: コピー先ディレクトリ (ドライブ:\パスまたは \\サーバー\共有\パス)。 ファイル :: コピーするファイル (名前/ワイルドカード: 既定値は「*.*」です) :: :: コピー オプション: :: /S :: サブディレクトリをコピーしますが、空のディレクトリはコピーしません。 /E :: 空のディレクトリを含むサブディレクトリをコピーします。 … /COPY:コピーフラグ :: ファイルにコピーする情報 (既定値は /COPY:DAT)。 (コピーフラグ: D= データ、A= 属性、T= タイムスタンプ)。 (S= セキュリティ =NTFS ACL、O= 所有者情報、U= 監査情報)。 … /DCOPY:コピーフラグ :: ディレクトリにコピーする情報 (既定値は /DCOPY:DA)。 (コピーフラグ: D= データ、A= 属性、T= タイムスタンプ)。 …
というわけで、こんな感じのオプションをつけて実行します。 (D:\Nintendo 3DS を C:\tmp\Nintendo 3DS にコピー)
C:\> ROBOCOPY "D:\Nintendo 3DS" "C:\tmp\Nintendo 3DS" /E /COPY:DAT /DCOPY:T
/COPY オプションで D を付け忘れるとファイルがコピーされないので注意です(しばらくハマった)。
うまくいくとこんな感じに出力されます。最後の「合計」と「コピー済み」が一致していればOKです。
------------------------------------------------------------------------------- ROBOCOPY :: Windows の堅牢性の高いファイル コピー ------------------------------------------------------------------------------- 開始: 2014年6月6日 3:58:21 コピー元 : D:\Nintendo 3DS\ コピー先 : C:\tmp\Nintendo 3DS\ ファイル: *.* オプション: *.* /S /E /DCOPY:T /COPY:DAT /R:1000000 /W:30 … 100% 新しいファイル 80 00000002.cmd 新しいディレクトリ 0 D:\Nintendo 3DS\Private\ 新しいディレクトリ 1 D:\Nintendo 3DS\Private\00020400\ 100% 新しいファイル 456024 phtcache.bin ------------------------------------------------------------------------------ 合計 コピー済み スキップ 不一致 失敗 Extras ディレクトリ: 30 30 0 0 0 0 ファイル: 26 26 0 0 0 0 バイト: 1.819 g 1.819 g 0 0 0 0 時刻: 0:00:10 0:00:09 0:00:00 0:00:01 速度: 215021863 バイト/秒 速度: 12303.649 MB/分 終了: 2014年6月6日 3:58:32
エクスプローラで見てみると、タイムスタンプも更新されず、そのままコピーできました。
というわけで
ペルソナQやりましょう
参考
*1:Windows Vista以降に含まれています
第10回記念シェル芸勉強会@シェルリアンタワー&第28回場所が未定だったが決まったぞ定例会に行ってきました
行ってきました
4月5日にGMO Yoursで開催された、第10回記念シェル芸勉強会@シェルリアンタワー&第28回場所が未定だったが決まったぞ定例会に行ってきました。
なお、今回は会場がGMOインターネット株式会社様ということで、VPS「ConoHa」の3000円クーポンもいただきました。 せっかくなのでいろいろ遊んでみようと思います。
気合の入ったクーポン券。デザイナーさんが超頑張ったとのこと。
今回学んだシェル芸
grep -o で1列に並べよう
通常、grepはマッチする行全体を出力しますが、-o(--only-matching)オプションを使用することで 行全体ではなくマッチする部分のみを出力します。
$ grep --help … Output control: … -o, --only-matching show only the part of a line matching PATTERN
これをQ4
次のようなファイルを作り、ファイルの中に三個存在する文字を出力してください。
ueda@remote:~$ cat hoge
aabbcdabbcccdd
で使うと、
$ echo aabbcdabbcccdd | grep -o . a a b b c d a b b c c c d d
のように出力できるので、あとはsortしてuniqしてgrepすればOK、というわけでした。
$ echo aabbcdabbcccdd | grep -o . | sort | uniq -c | grep 3 3 a 3 d
シェル芸では処理対象を「1行に1つ」の形に持っていくと処理しやすいことが多いので、こいつは大変便利です。
xargs で1行に並べよう
xargs といえば標準入力を読み込んで他のコマンドに引数として渡して実行するコマンドですが、 コマンドを指定しない場合はデフォルトの /bin/echo が実行されるため、結果として標準入力で 与えられたものを1行に並べるという動きをします。
xargs は、標準入力から空白や改行で区切られた一連の項目を読み込み (空白はダブルクォート、シングルクォート、バックスラッシュによって 保護できる)、それを引き数にして、指定した command を実行する (デフォルトのコマンドは /bin/echo である)。 このとき、ユーザが command に対して指定した引き数 (上記書式の initial-arguments) があれば、 xargs は標準入力から読み込んだ一連の項目をその後ろに 追加していく http://linuxjm.sourceforge.jp/html/GNU_findutils/man1/xargs.1.html
問題のQ2
スペースと数字と改行を使って次のようなファイルを作り、書いた数を足し算してください。
$ cat nums 1 2 3 4 5 6 7 8 9
では前述の grep -o で数値を1列に並べてawkで足し算、というのもアリですが、xargs を使って 数式を組み立てて bc に放り込むと変態度が上がります。
上記のファイルをそのまま xargs に渡すと
$ cat nums | xargs 1 2 3 4 5 6 7 8 9
となるので、あとは tr コマンドでスペースを + に置換して数式にしておき、
$ cat nums | xargs | tr ' ' '+' 1+2+3+4+5+6+7+8+9
bc コマンドに渡せばOK、というわけです。
$ cat nums | xargs | tr ' ' '+' | bc 45
このはちゃんはtcsh使い
きょうはUSP友の会勉強会とかいうこわいひとたちが来ているよ。みんなbashつかっているよ、こわいよー。ふつー、tcshだよー #usptomo http://t.co/CUSP2ByvR6
— 美雲このは (@MikumoConoHa) 2014, 4月 5
こわいよー。
まとめ
というわけで、シェル芸勉強会に参加してきました。 grep や xargs のようなよく使うコマンドも、掘り下げると知らない使い方が 見つかるもんですね。
「過負荷に耐えるWebの作り方 〜国民的アイドルグループ選抜総選挙の舞台裏」を読んだ
読んでみた
秒間10,000アクセスの処理が要件の、AKB48の選抜総選挙システムを構築した事例の解説本です。普段そんなにアクセスが来るシステムを触っていないということで、どんな仕組みなのかが気になって読んでみました。
過負荷に耐えるWebの作り方 ~国民的アイドルグループ選抜総選挙の舞台裏 (Software Design plus)
- 作者: 株式会社パイプドビッツ
- 出版社/メーカー: 技術評論社
- 発売日: 2013/12/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
システム面でおもしろかったこと
基本構成は真っ当な感じで、
なのですが、
『DBにはインメモリデータベースのVoltDBを採用』
というのが珍しいポイントでした。
実はこの本を読むまでVoltDBを知らなかったのですが、
ということで、NoSQLとRDBのいいとこ取り、といった特長を持っているようです。
ただしノードにまたがる集計、更新処理ではノード間の通信量が多くなり、一定量を超えると処理ができないケースがあったとのことで、現状ではあまりメジャーでないこともあり、注意が必要かもしれません。
なお、本の事例では障害時のデータ復旧のためにアプリケーション側でローカルファイルにデータを書き込んでいるとのことでしたが、VoltDBにはデータ永続化機能としてスナップショットを保存する機能*1があるようなので、用途によってはこちらでもいけそうです。
その他の感想
「秒間10,000アクセスが処理できること」という要件ですが、想定では瞬間最大値として秒間10,000アクセスあるかもしれないという話だったのが、いつの間にか営業担当者とお客さんの間で連続秒間10,000アクセスという話になっていた(しかも実際は全然そんなにアクセスが集中しなかった)ということで、無駄じゃんそれ…というのが正直な感想でした。
とは言え、こういった極端な要件をこなすにあたっては実現の上で多くの知見が得られる面もあるので、一度ぐらいはあってもいいのかもしれませんね。
SinatraでModularスタイルのときのテストでハマってた話
ざっくりまとめると
SinatraのModulerスタイルで書いたときは、RSpecなどでテストするときに上書きするRack::Testのappメソッドを
def app Sinatra::Application end
ではなく
def app HelloSinatra end
みたいに、アプリケーションのクラス(上記の場合はHelloSinatra)を返すようにしないとテストがうまく動かないという話です。
環境
なにごと?
Testing Sinatra with Rack::Testを見つつこんな感じのコードとテストを書いてたわけですよ。
# app.rb require 'sinatra/base' class HelloSinatra < Sinatra::Base get '/' do 'Hello, Sinatra!' end end
# spec/requests/hello_spec.rb ENV['RACK_ENV'] = 'test' require File.join(File.dirname(__FILE__), '..', '..', 'app.rb') require 'sinatra' require 'rack/test' require 'rspec' describe 'HelloSinatra' do include Rack::Test::Methods def app Sinatra::Application end it 'should be OK' do get '/' expect(last_response).to be_ok end end
で、テストすると失敗するわけです。
$ rspec F Failures: 1) HelloSinatra should be OK Failure/Error: expect(last_response).to be_ok expected ok? to return true, got false # ./spec/requests/hello_spec.rb:18:in `block (2 levels) in <top (required)>' Finished in 0.03914 seconds 1 example, 1 failure Failed examples: rspec ./spec/requests/hello_spec.rb:16 # HelloSinatra should be OK
なんでかなーと思ってModular vs. Classic Style - Sinatra: READMEを見つつ考えてみると、Testing Sinatra with Rack::TestのSinatra+RSpecのサンプルはClassicスタイルで
require 'sinatra' get '/' do 'Hello world!' end
って感じで書いてあります。 で、Classicスタイルだとconfig.ruは
require './app' run Sinatra::Application
のようにSinatra::Applicationを起動します。 これはきっとClassicスタイルの場合はルータを定義したりするとSinatra::Applicationが拡張されていくってことかな(TODO: ちゃんと調べる)。
それに対してModulerスタイルで
require 'sinatra/base' class HelloSinatra < Sinatra::Base get '/' do 'Hello, Sinatra!' end end
ってやるときは、config.ruは
require './app' run HelloSinatra
のように、アプリケーションのクラスから起動します。
…ということはModulerスタイルの場合、RSpecでもappメソッドはSinatra::ApplicationではなくHelloSinatraを返さなきゃダメなんじゃないだろうか、ということで
# spec/requests/hello_spec.rb ENV['RACK_ENV'] = 'test' require File.join(File.dirname(__FILE__), '..', '..', 'app.rb') require 'sinatra' require 'rack/test' require 'rspec' describe 'HelloSinatra' do include Rack::Test::Methods def app HelloSinatra # ←Sinatra::Applicationから変更 end it 'should be OK' do get '/' expect(last_response).to be_ok end end
のように書きなおしてみると…
$ rspec . Finished in 0.03378 seconds 1 example, 0 failures
うまくいった!
まとめ
というわけで、Sinatraの動きをもう少しちゃんと調べましょうというお話でした。
ruby-opencvの進捗の話(2014年2月版)
はじめに
なんか気がついたら2014年も1ヶ月が過ぎてますが、ruby-opencvのお話です。 前回からバージョンもだいぶ上がり、機能も地味にいろいろ追加されてるので、ちょっとだけ紹介します。
APIリファレンス的なものを(ようやく)用意しました
前からちょっとずつYARDで書いてたアレをようやくマージしました。 rubydoc.infoで見れるのでどうぞ。
微妙に網羅できてないのもありますが、よく使うやつはだいたい書いてあります。
FaceRecognizerを追加しました
FaceRecognizer #17 でご要望を頂いておきながらずーっと放っておいたFaceRecognizerが(v0.0.11から)使えるようになりました。 公式のチュートリアル Face Recognition with OpenCV に相当するサンプルも用意してあるので、興味のある方はぜひどうぞ。
https://github.com/ruby-opencv/ruby-opencv/tree/master/examples/facerec
FaceRecognizer(EigenFaces)のサンプルコード
せっかくなので、FaceRecognizerのEigenFacesを使って顔認識してみましょう。 Ubuntu 13.10 + Ruby 2.1.0-p0(x86_64-linux) + ruby-opencv 0.0.12 で動作確認していますが、だいたいどの環境でも同じように動くはずです。
1. 認識用の顔画像を AT&T Facedatabase から取ってくる
http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html から認識用の顔画像を取ってきて展開します。
$ wget http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip $ unzip att_faces.zip
2. テストデータを用意する
学習用に顔画像をラベルと対応付けたファイルを作成します。 OpenCV公式チュートリアルのこれを使ってもいいですが、 Ruby版のcreate_csv.rbも作ったので今回はこっちを使いましょう。
# create_csv.rb if ARGV.size != 1 puts "usage: ruby #{__FILE__} <base_path>" exit end BASE_PATH = ARGV[0] SEPARATOR = ';' label = 0 Dir.glob("#{BASE_PATH}/*").each { |dir| if FileTest::directory? dir Dir.glob("#{dir}/*") { |filename| puts "#{filename}#{SEPARATOR}#{label}" } label += 1 end }
画像ファイルのフォルダを引数で指定して実行します。 結果は標準出力に出るので、適当にリダイレクトしてください。
$ ruby create_csv.rb att_faces > at.txt
実行すると、下記のように 画像ファイル名;ラベル というフォーマットで対応付けのファイルが作成されます。
$ cat at.txt att_faces/s34/2.pgm;0 att_faces/s34/3.pgm;0 att_faces/s34/8.pgm;0 att_faces/s34/4.pgm;0 att_faces/s34/5.pgm;0 att_faces/s34/10.pgm;0 att_faces/s34/9.pgm;0 att_faces/s34/7.pgm;0 att_faces/s34/6.pgm;0 att_faces/s34/1.pgm;0 ...
3. 顔認識してみる
こんな感じのプログラム(eigenfaces.rb)を作ります。
# eigenfaces.rb require 'opencv' include OpenCV def read_csv(filename, sepalator = ';') images = [] labels = [] open(filename, 'r') { |f| f.each { |line| path, label = line.chomp.split(sepalator) images << CvMat.load(path, CV_LOAD_IMAGE_GRAYSCALE) labels << label.to_i } } [images, labels] end if ARGV.size < 1 puts "usage: ruby #{__FILE__} <csv.ext>" exit 1 end fn_csv = ARGV.shift output_folder = ARGV.shift # 顔画像を読み込む images, labels = read_csv(fn_csv); height = images[0].rows; # 識別対象の顔画像は学習対象とは別にしておく test_sample = images.pop test_label = labels.pop # Eigenfacesのモデルを作成して学習 model = EigenFaces.new model.train(images, labels) # 識別処理 # 識別結果のラベルと一致度が返ってくる predicted_label, predicted_confidence = model.predict(test_sample) # 結果を表示 puts "Predicted class: #{predicted_label} / Actual class: #{test_label}" puts "Confidence: #{predicted_confidence}" w1 = GUI::Window.new('Predicted') w2 = GUI::Window.new('Actual') w1.show images[predicted_label] w2.show images[test_label] GUI::wait_key
で、実行します。引数は2で作ったファイルのファイル名です。
$ ruby eigenfaces.rb at.txt
実行結果はこんな感じ(左が識別結果で右が実際の顔)。どうやらそれっぽく動いているようです。
そんなわけで
modern.IEで配布されているWindowsの仮想マシンを64bit版Ubuntuにインストールしようとした話
環境
- Ubuntu 13.04 64bit
- VirtualBox 4.2.12
なにごと?
マイクロソフトがIEでのWebページの検証のために、modern.IE というサイトで各種バージョンのIEが入った仮想マシンを配布しています。
Linuxでの検証用にはVirtualBoxのVMが配布されていたので、試しにIE10入りのWindows7をUbuntuにインストールしようとしてみたのですが…
$ wget -i https://az412801.vo.msecnd.net/vhd/IEKitV1_Final/VirtualBox/Linux/IE10_Win7/IE10.Win7.For.LinuxVirtualBox_2.txt $ ls IE10.Win7.For.LinuxVirtualBox.part1.sfx IE10.Win7.For.LinuxVirtualBox.part3.rar IE10.Win7.For.LinuxVirtualBox.part5.rar IE10.Win7.For.LinuxVirtualBox.part2.rar IE10.Win7.For.LinuxVirtualBox.part4.rar IE10.Win7.For.LinuxVirtualBox_2.txt $ chmod +x IE10.Win7.For.LinuxVirtualBox.part1.sfx $ ./IE10.Win7.For.LinuxVirtualBox.part1.sfx zsh: そのようなファイルやディレクトリはありません: ./IE10.Win7.For.LinuxVirtualBox.part1.sfx
IE10.Win7.For.LinuxVirtualBox.part1.sfxあるのに…
sfxファイルの中身を調べてみると
$ file IE10.Win7.For.LinuxVirtualBox.part1.sfx IE10.Win7.For.LinuxVirtualBox.part1.sfx: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, stripped
32bit用の実行ファイルのようです。 OSが64bitなので、32bitの実行ファイルを使えるようにライブラリをインストールします。
$ sudo apt-get update $ sudo apt-get install libc6:i386 libstdc++6:i386
で、もう一度試してみると…
$ ./IE10.Win7.For.LinuxVirtualBox.part1.sfx
RAR SFX archive
Extracting from ./IE10.Win7.For.LinuxVirtualBox.part1.sfx
Extracting IE10 - Win7.ova 0%
…
どうやらうまくいったっぽいです。 あとはできあがったovaファイルをVirtualBoxにインポートすれば仮想マシンが使えるようになります。
参考
ruby-opencvがRuby 2.0で使えるようになりました
というわけで
気がついたらだいぶ時間が開いてしまいましたが、ようやくRuby 2.0に対応しました。
ruby-opencv | RubyGems.org | your community gem host
動作環境は
- Ruby 1.9.3, 2.0.0
- OpenCV 2.4.5
となっております。 例によってWindows用にはmingw32,mswin32用のコンパイル済みパッケージも用意してあります。
Ruby 2.0対応以外の変更点は、バグ修正やFat gem作成機能追加ぐらいなので、そろそろ新しい機能も入れたいところですね。 中途半端に手を付けたFaceRecognizerを次回ぐらいで入れたいなー、 などと考えております。あとはリファレンスも進めなければ…。
開発は以下のリポジトリでやっていますので、お気づきの点やご要望、イケてるPull Requestなど、お待ちしております。