「第9回寒中シェル芸勉強会&第27回バナナで釘が打てますUSP友の会定例会」の問題をコマンドプロンプトで解いてみた
概要
先日、「第9回寒中シェル芸勉強会&第27回バナナで釘が打てますUSP友の会定例会」(http://usptomo.doorkeeper.jp/events/8339)にリモートで参加しまして。
https://twitter.com/kunst1080/status/434556029561344000
当日は普通にFreeBSD上のzshとかbashとかでやりましたが、今日はその問題をWindows7上のコマンドプロンプト(cmd.exe)でやってみようと思います。
資料
コンセプト
今回の問題は、ファイル操作系がメインでした。ファイル操作はcmdでも普段から割とやる感じです。
普段のノリでcmd叩けばよし。詰んだらワンライナーにこだわらずさっくり!の心構えでいきましょう。
※cmd.exeはコマンド拡張機能・遅延環境変数の展開は有効にしておくこと。(/V オプションを付けて起動)
第1問
ファイルを、先頭1文字目の名前のディレクトリへ移動する
rem 1ファイルずつ作成。 copy nul apple copy nul avocado copy nul banana copy nul cinnamon copy nul melon mkdir a mkdir b mkdir c mkdir m rem echoでコマンドを確認 for /f "usebackq tokens=*" %a in (`dir /a-d /b`) do @(set X=%a && echo move !x! !X:~0,1!) rem echoを外して実行! for /f "usebackq tokens=*" %a in (`dir /a-d /b`) do @(set X=%a && move !x! !X:~0,1!) rem 結果確認 dir /s /b C:\usr\workspace\cmd\20140215\Q1\a C:\usr\workspace\cmd\20140215\Q1\b C:\usr\workspace\cmd\20140215\Q1\c C:\usr\workspace\cmd\20140215\Q1\m C:\usr\workspace\cmd\20140215\Q1\a\apple C:\usr\workspace\cmd\20140215\Q1\a\avocado C:\usr\workspace\cmd\20140215\Q1\b\banana C:\usr\workspace\cmd\20140215\Q1\c\cinnamon C:\usr\workspace\cmd\20140215\Q1\m\melon
第2問
ファイル名に含まれる空白をアンダーバーにしてリネームする
rem ファイル作るよ! copy nul "私は 蟹" copy nul "オシャレな 蟹" copy nul "足が 10本" rem echoでコマンドを確認 for /f "usebackq tokens=*" %a in (`dir /a-d /b`) do @(set X=%a&& echo ren "!x!" "!X: =_!") rem echoを外して実行! for /f "usebackq tokens=*" %a in (`dir /a-d /b`) do @(set X=%a&& ren "!x!" "!X: =_!") rem 結果確認 dir /b オシャレな_蟹 私は_蟹 足が_10本
問1とだいたい同じですね。
第3問
ディレクトリを適当に作って、20140101から20141231まで、日付に対応したファイルを作成。
フィアル内にはdateコマンドの実行結果を入れる。
普通にやるのは無理なので、有効な日付を判定するコマンドを適当に作成しておきます。
isDate.bat
rem コマンドを確認 for /L %a in (20140101,1,20141231) do @(call isdate %a && echo %a) rem リダイレクトを付けて実行! for /L %a in (20140101,1,20141231) do @(call isdate %a && echo %a>%a) rem 結果確認 dir /s /b
※処理超遅い>< のと、ファイルの中身は手抜き。
第4問
ファイルの中身を入れ替え
rem ファイル作るよ! echo カレー > a_ramen echo ラーメン > a_cury echo トマト > b_apple echo りんご > b_tomato rem (余談)UNIXではgrepを使いましたが、コマンドプロンプトではfindstrでファイルと中身を並べて確認できます。 findstr . * a_cury:ラーメン a_ramen:カレー b_apple:トマト b_tomato:りんご rem echoでコマンドを確認 (dir /w a_* && dir /w b_*) | findstr "a_ b_" | for /f "usebackq tokens=1,2" %a in (`findstr .*`) do @echo ren %a tmp && echo ren %b %a && echo ren tmp %b rem echoを外して実行! (dir /w a_* && dir /w b_*) | findstr "a_ b_" | for /f "usebackq tokens=1,2" %a in (`findstr .*`) do @ren %a tmp && ren %b %a && ren tmp %b rem 結果確認 findstr . * a_cury:カレー a_ramen:ラーメン b_apple:りんご b_tomato:トマト
第5問
問3のファイルを各月ごとにtar.gzファイルにする
tar.gzとか無理っす。
とりえずフォルダに分けときまーす
rem echoでコマンドを確認 for /f "usebackq tokens=*" %a in (`dir /b 2014*`) do @(set X=%a&& echo if not exist !X:~0,6! mkdir !X:~0,6! && echo move %a !X:~0,6!) rem echoを外して実行! for /f "usebackq tokens=*" %a in (`dir /b 2014*`) do @(set X=%a&& if not exist !X:~0,6! mkdir !X:~0,6! && move %a !X:~0,6!) rem エラー!?ちょっと構文を買えてやりなおし for /f "usebackq tokens=*" %a in (`dir /b 2014*`) do @(set X=%a&& echo if not exist !X:~0,6! mkdir !X:~0,6! && echo move %a !X:~0,6!)>> exec.bat && @cmd /c exec.bat rem なんかエラー出るけどファイルは移動するorz rem 結果確認 tree /f フォルダー パスの一覧 ボリューム シリアル番号は 3AC0-14F1 です C:. │ exec.bat │ ├─201401 │ 20140101 │ 20140102 │ 20140103 │ 20140104 以下略!
第6問
mkdir -p `jot -s / -b a 100` && touch `jot -s / -b a 100`/b && cd `jot -s / -b a 100` するやつ
rem 3階層くらいで実験 (for /L %a in (1,1,3) do mkdir a && cd a) && copy nul b cd ..\..\.. rd /s a rem 一気に実行! (for /L %a in (1,1,100) do mkdir a && cd a) && copy nul b rem 結果確認 echo %CD% C:\usr\workspace\cmd\20140215\Q6\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a\a
結果確認その2。
とりあえず、標準入力を指定文字で分割するスクリプトを作っておいた。
sepa.bat
これを使って、aディレクトリの数を以下のように確認できる。
echo %CD% | sepa "\\" echo %CD% | sepa "\\" | find /c "a"
第7問
先ほど作ったファイルbを、50番目のaディレクトリに移動する。
rem とりあえず、元のディレクトリに戻ってから。 rem ディレクトリ名を作成できるか実験 set X1= && (for /L %a in (1,1,100) do @set X1=!X1!a\) && echo !X1! rem いけそうなので実行。ただし、面倒なので分割実行。 set X1= && (for /L %a in (1,1,100) do @set X1=!X1!a\) && echo !X1! set X2= && (for /L %a in (1,1,50) do @set X2=!X2!a\) && echo !X2! move %X1%b %X2%b rem 結果確認 dir /s /b b dir /s /b b | sepa "\\" | find /c "a"
第8問
先ほど作ったディレクトリについて、rm -rを使わずに~/a以下のディレクトリを消去してください。
rm -r じゃなくて rd /s /q ・・・という冗談はさておき。delとrmdirで消していきます。
for /L %a in (1,1,99) do @cd a && for /L %a in (1,1,100) do @(rmdir a && cd .. && if exist b del b)
なぜか「ディレクトリが空ではありません。」というエラーが出るが、実際には空なのでディレクトリはちゃんと削除されてる。
一応、最後まで普通にやれました。