概要
先日、「第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文字目の名前のディレクトリへ移動する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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問
ファイル名に含まれる空白をアンダーバーにしてリネームする
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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
1
2
3
4
5
6
7
8
9
|
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問
ファイルの中身を入れ替え
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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とか無理っす。
とりえずフォルダに分けときまーす
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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
するやつ
1
2
3
4
5
6
7
8
9
10
11
12
|
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ディレクトリの数を以下のように確認できる。
1
2
3
|
echo %CD% | sepa "\\"
echo %CD% | sepa "\\" | find /c "a"
|
第7問
先ほど作ったファイルbを、50番目のaディレクトリに移動する。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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で消していきます。
1
2
|
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)
|
なぜか「ディレクトリが空ではありません。」というエラーが出るが、実際には空なのでディレクトリはちゃんと削除されてる。
一応、最後まで普通にやれました。