第９回 シェル芸勉強会

シェル芸（マウスをつかわず、ソースコードものこさず、 GUI ツールを立ちあげる間もなく、あらゆる調査・計算・テキスト処理を CLI 端末へのコマンド入力一撃で終わらす）の勉強会で出題された問題をバッチファイルで解いてみました。

上田ブログ
http://blog.ueda.asia/?p=1955

```bat:2014-02-15.bat
@echo off

set SELF=%~n0
set HELP=Usage: %SELF% NUMBER
set HOME=%~dps0
set HOME=%HOME:~0,-1%

setlocal enabledelayedexpansion
  :: 位置パラメーターを確認
  if "%~1" == "" (
    echo %HELP% >&2
    exit /b 1
  )
  :: 値が数値か確認
  (echo %~1) | findstr /r "[^0-9]." > NUL
  if %ERRORLEVEL% equ 0 (
    echo %HELP% >&2
    exit /b 1
  )
  
  :: 位置パラメーターを取得
  set n=%~1
  
  :: 値が範囲内か確認(Q1からQ8まで)
  if %n% lss 1 (
    echo %SELF%: illegal value: use 1-8 >&2
    exit /b 1
  )
  if %n% gtr 8 (
    echo %SELF%: illegal value: use 1-8 >&2
    exit /b 1
  )
  
  :: 作業フォルダーを作成
  set CWD=%HOME%\A%n%
  md %CWD%
  
  :: テストを実行
  call :A%n% %CWD%
  if %ERRORLEVEL% neq 0 (
    echo %SELF%: script abended: A%n% >&2
    exit /b 1
  )
  
  :: 作業フォルダーを削除
  cd %CWD%\..
  rd /s /q %CWD%
endlocal
goto :EOF

:A1
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: ファイルを作成
  for %%f in (apple avocado banana cinnamon melon) do (
    copy NUL %CWD%\%%f > NUL
  )
  :: フォルダーを作成
  for %%d in (a b c m) do (
    md %CWD%\%%d
  )
  
  :: ファイルをフォルダーに移動
  for %%f in (%CWD%\*) do (
    set t=%%~nxf
    move %CWD%\!t! %CWD%\!t:~0,1!
  )
  
  :: 結果を表示
  echo.
  tree /f %CWD%
endlocal
goto :EOF

:A2
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: ファイルを作成
  for %%f in ("私は 蟹" "オシャレな 蟹" "足が 10本") do (
    copy NUL "%CWD%\%%~f" > NUL
  )
  
  :: 結果を表示
  echo.
  echo ^-^- 変換前 ^-^-
  dir /b %CWD%
  
  :: ファイル名を変更
  for %%f in (%CWD%\*) do (
    set f=%%~nxf
    move "%CWD%\!f!" %CWD%\!f: =_!
  )
  
  :: 結果を表示
  echo.
  echo ^-^- 変換後 ^-^-
  dir /b %CWD%
endlocal
goto :EOF

:A3
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: カレンダーを表示するバッチファイルが存在するか確認
  if not exist "%HOME%\cal.bat" (
    echo %SELF%: file not found: %HOME%\cal.bat >&2
    exit /b 1
  )
  
  :: カレンダーを表示するバッチファイルを実行して日付を取得
  set y=2014
  for /l %%m in (1,1,12) do (
    set t=
    for /f "tokens=*" %%t in ('cal %%m %y% ^| more +2') do (
      set t=!t! %%t
    )
    set m=%%m
    if !m! lss 10 (
      set m=0!m!
    )
    for %%d in (!t!) do (
      set d=%%d
      if !d! lss 10 (
        set d=0!d!
      )
      (echo %y%/!m!/!d!) > %CWD%\%y%!m!!d!
    )
  )
  
  :: 結果を表示
  echo.
  dir /w %CWD%
endlocal
goto :EOF

:A4
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: ファイルを作成
  > %CWD%\a_ramen  echo カレー
  > %CWD%\a_cury   echo ラーメン
  > %CWD%\b_apple  echo トマト
  > %CWD%\b_tomato echo りんご
  
  :: 結果を表示
  echo.
  echo ^-^- 変換前 ^-^-
  findstr /r ".*" %CWD%\*
  
  :: ファイル名を変更
  for %%s in (a b) do (
    set t=
    for /f "tokens=*" %%f in ('dir /b %CWD%\%%s_*') do (
      set t=%%f !t!
    )
    for /f "tokens=1,2" %%a in ("!t!") do (
      move %CWD%\%%a %CWD%\%SELF%.tmp
      move %CWD%\%%b %CWD%\%%a
      move %CWD%\%SELF%.tmp %CWD%\%%b
    )
  )
  
  :: 結果を表示
  echo.
  echo ^-^- 変換後 ^-^-
  findstr /r ".*" %CWD%\*
endlocal
goto :EOF

:A5
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: ファイルを圧縮・展開するコマンドが存在するか確認
  for %%f in (makecab.exe expand.exe) do (
    if not exist "%%~$PATH:f" (
      echo %SELF%: file not found: %%f >&2
      exit /b 1
    )
  )
  
  :: テスト 3を実行
  call :A3 %CWD%
  if %ERRORLEVEL% neq 0 (
    echo %SELF%: script abended: A3 >&2
    exit /b 1
  )
  
  :: 月単位のフォルダーを作成しながらファイルを移動
  for %%f in (%CWD%\*) do (
    set f=%%~nxf
    set d=!f:~0,6!
    if not exist "%CWD%\!d!\" (
      md %CWD%\!d!
    )
    move %CWD%\!f! %CWD%\!d!
  )
  
  :: 結果を表示
  echo.
  tree /f %CWD%
  
  :: ファイルを圧縮
  for /f "tokens=*" %%d in ('dir /ad /b %CWD%') do (
    set t=%%~nd
    copy NUL %CWD%\!t!.tmp > NUL
    for %%f in (%CWD%\%%d\*) do (
      (echo %%f) >> %CWD%\!t!.tmp
    )
    makecab /f %CWD%\!t!.tmp               ^
            /d InfFileName=NUL             ^
            /d RptFileName=NUL             ^
            /d DiskDirectoryTemplate=%CWD% ^
            /d CabinetNameTemplate=!t!.cab
    if !ERRORLEVEL! neq 0 (
      echo %SELF%: failed to compress: !t!.cab >&2
      exit /b 1
    )
    del %CWD%\!t!.tmp
  )
  
  :: 結果を表示
  for %%f in (%CWD%\*.cab) do (
    set f=%%~nxf
    echo.
    echo ^-^- !f! ^-^-
    expand -d %%f
    if !ERRORLEVEL! neq 0 (
      echo %SELF%: failed to expand: !f! >&2
      exit /b 1
    )
  )
endlocal
goto :EOF

:A6
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: パス文字列を生成
  for /l %%i in (1,1,100) do (
    set t=!t!\a
  )
  
  :: フォルダーを作成
  md %CWD%\%t%
  
  :: 最下層のフォルダーへ移動
  pushd %CWD%\%t%
  
  :: ファイルを作成
  copy NUL b > NUL
  
  :: 結果を表示
  echo.
  cd
  
  echo.
  dir %CWD%\%t%
  
  set i=0
  set p=!CD:%CWD%=!
  for %%i in (%p:\= %) do (
    set /a i+=1
  )
  echo.
  echo %SELF%: # of folders: %i%
  
  :: 作業フォルダーへ移動
  popd
endlocal
goto :EOF

:A7
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: テスト 6を実行
  call :A6 %CWD%
  if %ERRORLEVEL% neq 0 (
    echo %SELF%: script abended: A6 >&2
    exit /b 1
  )
  
  :: パス文字列を生成
  for /l %%i in (1,1,100) do (
    set t1=!t1!\a
  )
  for /l %%i in (1,1,50) do (
    set t2=!t2!\a
  )
  
  :: ファイルが存在するか確認
  if not exist "%CWD%\%t1%\b" (
    echo %SELF%: file not found: %CWD%\%t1%\b >&2
    exit /b 1
  )
  
  :: ファイルを移動
  move %CWD%\%t1%\b %CWD%\%t2%
  
  :: 50番目のフォルダーへ移動
  pushd %CWD%\%t2%
  
  :: 結果を表示
  echo.
  dir
  
  set i=0
  set p=!CD:%CWD%=!
  for %%i in (%p:\= %) do (
    set /a i+=1
  )
  echo.
  echo %SELF%: # of folders: %i%
  
  :: 作業フォルダーへ移動
  popd
endlocal
goto :EOF

:A8
setlocal enabledelayedexpansion
  set CWD=%~1
  
  :: テスト 6を実行
  call :A6 %CWD%
  if %ERRORLEVEL% neq 0 (
    echo %SELF%: script abended: A6 >&2
    exit /b 1
  )
  
  :: パス文字列を生成
  for /l %%i in (1,1,100) do (
    set t=!t!\a
  )
  
  :: 最下層のフォルダーへ移動
  cd %CWD%\%t%
  
  :: 結果を表示
  echo.
  cd
  
  :: 上の階層へ移動しながらフォルダーを削除
  for /l %%i in (1,1,100) do (
    if exist ".\b" (
      del /q .\b
    )
    cd ..
    rd .\a
  )
  
  :: 結果を表示
  echo.
  dir
endlocal
goto :EOF
```

位置パラメーターを指定せずに実行すると

```
C:\temp>2014-02-15.bat
Usage: 2014-02-15 NUMBER
```

とヘルプが表示されるので、 1 から 8 までの数字のなかから任意の値を指定して実行してください。