Language detail: Batchfile
Coverage: 27.41%
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- 文字列で+を表示する (Nested Flatten)
- 年賀はがきの当せん番号 (Nested Flatten)
- 箱詰めパズルの判定 (Nested Flatten)
- 関数やメソッドのソースの平均行数 (Nested Flatten)
- コレクションの実装 (Nested Flatten)
codes
バイナリクロック
(Nested
Flatten)
バッチで。 時分秒を 6桁で表示します。 callを使用するとサブルーチンを呼び出す分だけ時間がかかり、正 確に 1秒を刻めなくなってしまうので、処理をすべて展開しました。 # なお、12行目は 2桁の数値の上位桁が 0である時、 8進数として # 解釈されないようにするための処理です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @echo off
setlocal enabledelayedexpansion
set m=0
set n=0
set s=
set t=
:_
for /f "delims=." %%t in ("%TIME%") do set t=%%t
cls
for %%t in (%t::= %) do (
set /a n=1%%t-100
set s=
for /l %%i in (1,1,6) do (
set /a m=n%%2
if !m! equ 0 (set s=□!s!) else (set s=■!s!)
set /a n/=2
)
echo !s!
)
ping -n 2 127.0.0.1 > NUL
goto _
endlocal
|
初期設定の読み書き
(Nested
Flatten)
参考ページを見ると、設定ファイルがなくても設定を読み書きできる方法のことを言っている?
バッチファイルでレジストリの値を取得するコードを書きました。reg.exe呼んでるだけですが。
バッチファイルでレジストリの値を取得するコードを書きました。reg.exe呼んでるだけですが。
see: Preferences API 入門
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ===== getreg.bat =====
@echo off
rem reg.exeの結果を1行ごと%rに格納する
for /F "usebackq delims=" %%r in (`reg.exe QUERY %1 /v %2`) do (
rem %rをタブ区切りデータとみなし、3列目を%tに格納する
for /F "tokens=3 delims= " %%t in ("%%r%") do (
rem %tが空でなければ、レジストリ値だとみなす
if not "%%t%" == "" (
echo %%t%
goto e
)
)
)
:e
===== 使用例 caller.bat =====
@echo off
for /F "usebackq delims=" %%v in (`call getreg "HKEY_CURRENT_USER\Control Panel\Desktop" Wallpaper`) do set WALLPAPER=%%v%
echo 壁紙=[%WALLPAPER%]
for /F "usebackq delims=" %%v in (`call getreg "HKEY_CURRENT_USER\Control Panel\Colors" ActiveTitle`) do set ACTIVETITLE=%%v%
echo タイトルバーの色=[%ACTIVETITLE%]
|
正整数のゲーデル数化?
(Nested
Flatten)
> バッチファイル内でサブルーチンは無理です... よね?
setlocalとendlocalで変数のスコープを区切り、callと:EOFを組み
合わせればできます。
バッチなので限界はありますが、整数 nの桁数に応じて素数を生成
するようにしました。
素数を生成する部分もサブルーチンにしたかったのですが、戻り値
に複数の値(擬似的な配列)を返すことができなかったので、そこは
あきらめました。
e.g.
C:\>@echo off & (for %n in (9 81 230) do #100.bat %n) & echo on
512
768
108
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | @echo off
setlocal enabledelayedexpansion
set G=1
set i=0
set j=0
set k=1
set l=0
set n=%~1
set p=
set t=0
set v=0
set x=1
(echo %n%) | findstr /r [0-9] > NUL 2>&1 || (echo usage: %~n0 NUMBER >&2 & exit /b 1)
call :length %n% l
:: 素数を生成
set p[0]=2
:LOOP_1
if %k% geq %l% goto BREAK
set /a x+=2
set j=0
:LOOP_2
if %j% lss %k% (
set /a t=x%%!p[%j%]!
if !t! neq 0 (
set /a j+=1
goto LOOP_2
)
)
if %j% equ %k% (
set p[!k!]=%x%
set /a k+=1
)
goto LOOP_1
:BREAK
set /a l-=1
for /l %%i in (0,1,%l%) do (
call :power !p[%%i]! !n:~%%i,1! v
set /a G*=v
)
endlocal & echo %G%
goto :EOF
:length
setlocal enabledelayedexpansion
set i=0
set t=%~1
if not "%t%" == "" (
:_
set t=!t:~1!
set /a i+=1
if not "!t!" == "" goto _
)
endlocal & set %~2=%i%
goto :EOF
:power
setlocal
set n=1
for /l %%i in (1,1,%~2) do set /a n*=%~1
endlocal & set %~3=%n%
goto :EOF
|
NT系のCMD.EXEでは、SET /Aで計算ができます。
このコード、goedel.batという名で保存してください。バッチファイルが体を張って関数goedelという形態になっているということにさせてください。さすがにバッチファイル内でサブルーチンは無理です……よね?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @ECHO OFF
If NOT "%1"=="/R" (
CALL %0 /R %1 2 3 5 7 11
GOTO EXIT
)
SET /A G = 1
SET /A T = %2
:NEXT
SET /A N = %T:~0,1% + 0
FOR /L %%I IN (1, 1, %N%) DO SET /A G *= %3
SET /A T = %T:~1% + 0
SHIFT
IF NOT "%T%"=="0" GOTO NEXT
ECHO %G%
:EXIT
|
ケブンッリジ関数
(Nested
Flatten)
バッチで。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | @echo off
setlocal enabledelayedexpansion
set n=0
set s=
set t=
set w=
if "%~1" == "" (echo usage: %~n0 FILE >&2 & exit /b 1)
for /f "tokens=*" %%l in (%~1) do (
set t=
for %%w in (%%l) do (
set w=%%w
call :length !w! n
if !n! gtr 3 (
call :shuffle !w:~1,-1! s
set t=!t!!w:~0,1!!s!!w:~-1!
) else (
set t=!t!!w!
)
)
echo !t!
)
endlocal
goto :EOF
:shuffle
setlocal enabledelayedexpansion
set i=0
set j=0
set m=0
set n=0
set t=
set w=%~1
set v=0
call :length %w% n
for /l %%i in (0,1,%n%) do set v[%%i]=%%i
set i=0
:L1
set /a j=%RANDOM%%%%n%
set v=!v[%i%]!
set v[%i%]=!v[%j%]!
set v[%j%]=%v%
set /a i+=1
if %i% lss %n% goto L1
set i=0
:L2
set m=!v[%i%]!
set t=%t%!w:~%m%,1!
set /a i+=1
if %i% lss %n% goto L2
endlocal & set %~2=%t%
goto :EOF
:length
setlocal enabledelayedexpansion
set i=0
set t=%~1
if not "%t%" == "" (
:_
set t=!t:~1!
set /a i+=1
if not "!t!" == "" goto _
)
endlocal & set %~2=%i%
goto :EOF
|
指定コマンドを別プロセスで起動
(Nested
Flatten)
バッチで外部コマンドを利用する場合は、自ずと別プロセスで実行
されます。なので、ビルトインコマンドを実行した場合でも別プロ
セスを生成してから実行するようにしました。実行結果と終了ステ
ータスは標準出力に出力します。
# コマンド文字列にリダイレクトやパイプといった特殊な文字が含
# まれる場合は、 ^(ハット)でエスケープする必要があります。
以下は、tasklistコマンドでコマンドを実行する前と実行した後の
差分を並べたものです。
e.g.
実行前
イメージ名 PID
========================= ========
(中略)
cmd.exe 2776
cmd.exe 3236
tasklist.exe 3308
wmiprvse.exe 3336
実行後
イメージ名 PID
========================= ========
(中略)
cmd.exe 2776
cmd.exe 3236
wmiprvse.exe 3336
cmd.exe 3368 ← 別プロセスで実行
tasklist.exe 3376
Windows XPで動作を確認しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @echo off
setlocal
set c=%~1
set f=%~fs0.%RANDOM%
set ?=0
if "%c%" == "" (echo usage: %~n0 COMMAND) & exit /b 1
cmd /c "%c%" > %f% 2>&1
set ?=%ERRORLEVEL%
echo.
echo 実行結果
type %f%
echo.
echo 終了ステータスは %?% です。
del %f%
endlocal & exit /b 0
|
ACLの制御
(Nested
Flatten)
あ、これはどうもご丁寧に。 CREATOR OWNERは知りませんでした。ちょっと調べてみたのですが、 ファイルを作成すると暗黙的に CREATOR OWNER(作成者・所有者)に 所属するようですね。 お題の「作成者以外読み書きできないようにする」は、言い換えれ ば「作成者だけが読み書きできるようにする」ということなので、 CREATOR OWNERの ACLを設定するのが筋だったかもしれません。 ただ、[ユーザーまたはグループの選択]ダイアログで検索したり、 [コンピューターの管理] - [ローカルユーザーとグループ] を見て も CREATOR OWNERというエントリが見当たらないんですよね。 # ACLの操作云々よりも、先に Windowsの ACLの仕組みを学ぶべき # だったか orz
テキスト行の正規化
(Nested
Flatten)
バッチで。 ファイルやコマンドの実行結果を解析する際、 for文が空行を暗黙 的に読み飛ばしてしまうので、その点を findstrコマンドで補って います。 なお、パディング用の文字に半角空白を指定することはできません。 これはechoコマンドの仕様に依存するためです。 あと、バッチではマルチバイト文字をバイト単位で扱うことができ ないため、シングルバイトとマルチバイトが混在するファイルには 対応できていません。 Windows XPで動作を確認しました。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | @echo off
setlocal enabledelayedexpansion
set c=%~2
set f=%~1
set i=0
set l=0
set m=0
if not exist "%f%" (
echo usage: %~n0 FILE CHARACTER >&2
exit /b 1
)
call :length "%c%" l
if %l% neq 1 (
echo usage: %~n0 FILE CHARACTER >&2
exit /b 1
)
for /f "tokens=1,2 delims=:" %%i in ('findstr /n /v /r "^$" %f%') do (
set s[%%i]=%%j
call :length "%%j" l[%%i]
if !l[%%i]! gtr !m! set m=!l[%%i]!
set /a i+=1
)
:: 空行
for /f "delims=:" %%i in ('findstr /n /r "^$" %f%') do (
set s[%%i]=
set l[%%i]=0
set /a i+=1
)
for /l %%i in (1,1,%i%) do (
set /a n=m-!l[%%i]!
for /l %%j in (1,1,!n!) do set s[%%i]=!s[%%i]!%c%
echo !s[%%i]!
)
endlocal & exit /b 0
goto :EOF
:length
setlocal enabledelayedexpansion
set i=0
set t=%~1
if not "%t%" == "" (
:_
set t=!t:~1!
set /a i+=1
if not "!t!" == "" goto _
)
endlocal & set %~2=%i%
goto :EOF
|
キッチンタイマー
(Nested
Flatten)
こんな感じでも書けますね。 あまり大きな数を指定されると 1秒を刻めなくなってしまいますが、 そのような場合は 8行目を削除してください。 なお、14行目の行末は BL(Ctrl + G) です。制御コードの一つです が、 コピー & ペーストで問題無く復元できると思います。 Windows XPで動作を確認しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @echo off
setlocal enabledelayedexpansion
if "%~1" == "" (echo usage: %~n0 SECOND) & exit /b 1
for /l %%i in (%~1,-1,1) do (
cls
set t=
for /l %%j in (1,1,%%i) do set t=!t!^|
echo !t! %%i
ping -n 2 127.0.0.1 > NUL
)
cls
echo
endlocal
|
ACLの制御
(Nested
Flatten)
バッチというよりは、もはや外部コマンドの使い方になってしまう
のですが、 Windowsでは cacls.exe (Change ACLS)を利用します。
が、
読み取り権限と書き込み権限だけ付与したはずなのに、後者を付与
した段階で実行権限も付与されてしまいました。実行権限だけ無効
にするといった細かい設定はxcacls.exeを利用しないとできないの
かもしれません。
e.g.
:: ファイルを作成
C\:>(echo @date /t) > #244.bat
:: 読み取り権限を付与
C\:>echo y|cacls #244.bat /p USERDOMAIN\username:r
:: 書き込み権限を付与
C\:>echo y|cacls #244.bat /e /g USERDOMAIN\username:w
:: アクセス制御リストを確認
C\:>cacls #244.bat
C:\#244.bat USERDOMAIN\username:(特殊なアクセス:)
READ_CONTROL
SYNCHRONIZE
FILE_GENERIC_WRITE
FILE_WRITE_DATA
FILE_APPEND_DATA
FILE_WRITE_EA
FILE_EXECUTE ← ?
FILE_WRITE_ATTRIBUTES
(別のユーザーでログオン)
:: ファイルを読み込む
C\:>type #244.bat
アクセスが拒否されました。
:: ファイルに書き込む
C\:>(echo @time /t) > #244.bat
アクセスが拒否されました。
:: ファイルを実行
C\:>#244.bat
アクセスが拒否されました。
# Windows XPで動作を確認しました。
クリップボードへの転送
(Nested
Flatten)
バッチでは実現できないので、外部コマンドclip.exeを使用します。
clip.exeは Windows Server 2003から標準で同梱されるようになり
ました。
ファイルの内容を標準入力を介してクリップボードに転送すること
ができます。
e.g.
C:\>clip < #188.txt
コマンドの実行結果を標準出力を介してクリップボードに転送し、
クリップブックで表示することもできます。
e.g.
C:\>(for %i in (%PATH:;= %) do @echo %i) | clip & clipbrd
私はWindows XPを使用しているので、 Microsoftの FTPサイトから
ダウンロードしてきたもので動作確認を行いました。
ref.
ftp://ftp.microsoft.com/Services/TechNet/samples/ps/win98/reskit/file/clip.exe
IPv6アドレスの短縮
(Nested
Flatten)
バッチで。
e.g.
C:\>226.bat 1230:5670:0000:0000:0123:0000:0000:00ab
1230:5670::123:0:0:ab
C:\>226.bat 0000:0000:0000:0000:0000:0000:0000:0001
::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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | @echo off
setlocal enabledelayedexpansion
set #=0
set i=0
set t=
set v=%~1
if "%v%" == "" (echo usage: %~n0 IPV6_ADDRESS >&2) & exit /b 1
for %%v in (%v::= %) do (
set /a #+=1
set v[!#!]=%%v
)
if %#% lss 8 (echo usage: %~n0 IPV6_ADDRESS >&2) & exit /b 1
for /l %%i in (1,1,%#%) do (
set /a x=0x!v[%%i]!
call :X !x! v[%%i]
)
for /l %%i in (1,1,%#%) do (
if !v[%%i]! equ 0 (set i=%%i) & goto BREAK_1
if %%i gtr 1 set t=!t!:
set t=!t!!v[%%i]!
)
:BREAK_1
for /l %%i in (%i%,1,%#%) do (
if !v[%%i]! neq 0 goto BREAK_2
set i=%%i
)
:BREAK_2
if %i% gtr 0 (
set t=!t!:
if %i% equ %#% (
set t=!t!:
) else (
set /a i+=1
for /l %%i in (!i!,1,%#%) do set t=!t!:!v[%%i]!
)
)
echo %t%
endlocal & exit /b 0
goto :EOF
:X
setlocal enabledelayedexpansion
set m=
set q=%~1
set t=
set x=0123456789abcdef
:_
set /a m=%q%%%16
set /a q=%q%/16
set t=!x:~%m%,1!%t%
if %q% gtr 0 goto _
endlocal & set %~2=%t%
goto :EOF
|
外部の実行ファイルを呼び出し
(Nested
Flatten)
お題の意図が「呼び出し先のプログラムが終了するまで呼び出し元
のプログラムを待機させる」ということであれば、 startコマンド
のwaitオプションで実現できそうです。
e.g.
C:\>start /wait ping -n 5 127.0.0.1 && echo 復帰しました。
C:\>start ping -n 5 127.0.0.1 && echo 復帰しました。
# Windows XPで動作を確認。
ミリ秒まで含んだ時刻文字列
(Nested
Flatten)
バッチで。 10ミリ秒単位までしか表現できないので、末尾に 0を補っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @echo off
setlocal
set d=
set t=
chcp 932 > NUL
for /f %%d in ('date /t') do set d=%%d
for /f "tokens=2" %%t in ('echo. ^| time') do set t=%%t
echo %d:/=%%t::=%0
endlocal
|
指定ファイル名でフォルダツリーごとコピー
(Nested
Flatten)
バッチで。
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 30 31 32 33 34 | @echo off
setlocal enabledelayedexpansion
set #=0
set d=
set f=
set p=
set s=
for %%v in (%*) do set /a #+=1
if %#% lss 3 (
echo usage: %~n0 SOURCE DESTINATION FILE [FILE ...] >&2
exit /b 1
)
(set s=%~fs1) & shift
(set d=%~fs1) & shift
:_
set f=%f%%1
shift
if not "%1" == "" goto _
rd /s /q %d% 2> NUL
for %%f in (%f%) do (
for /r "%s%" %%p in (%%f) do (
if exist "%%p" (
set p=%%p
set p=!p:%s%=%d%!
if not exist "!p:%%f=!" md !p:%%f=!
copy /y %%p !p! > NUL && echo !p!
)
)
)
endlocal
|
漢数字で九九の表
(Nested
Flatten)
バッチで。
環境変数ERRORLEVELに無理矢理値を代入すると、終了ステータスが
1になる性質を利用しています。
e.g.
C:\>212.bat
一 二 三 四 五 六 七 八 九
二 四 六 八 一〇 一二 一四 一六 一八
三 六 九 一二 一五 一八 二一 二四 二七
四 八 一二 一六 二〇 二四 二八 三二 三六
五 一〇 一五 二〇 二五 三〇 三五 四〇 四五
六 一二 一八 二四 三〇 三六 四二 四八 五四
七 一四 二一 二八 三五 四二 四九 五六 六三
八 一六 二四 三二 四〇 四八 五六 六四 七二
九 一八 二七 三六 四五 五四 六三 七二 八一
なお、19行目のcall set ...の部分は以下を参考にしました。
see: 漢数字で九九の表を出力するバッチファイル
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 | @echo off
setlocal enabledelayedexpansion
set 〇=%ERRORLEVEL%
set ERRORLEVEL=
set 一=%ERRORLEVEL%
set i=%〇%
for %%i in (一 二 三 四 五 六 七 八 九) do (
set /a i+=%一%
set %%i=!i!
)
for /l %%i in (%一%,%一%,%九%) do (
set t=
for /l %%j in (%一%,%一%,%九%) do (
set /a v=%%i*%%j
set /a q=!v!/%一%%〇%
for %%i in (〇 一 二 三 四 五 六 七 八 九) do call set v=%%v:!%%i!=%%i%%
if !q! equ %〇% set v= !v!
set t=!t! !v!
)
echo !t!
)
endlocal
|
ファイルサイズの取得
(Nested
Flatten)
Windows NTでは無理ですが、これで。
e.g.
C:\>#243.bat A.txt B.txt
C:\A.txt 1024
C:\B.txt 2048
1 2 3 4 5 | :: #243.bat
@echo off
for %%i in (%*) do (
if exist "%%~fi" echo %%~fi %%~zi
)
|
タブ区切りデータの処理
(Nested
Flatten)
next >>
バッチで。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @echo off
setlocal enabledelayedexpansion
set a=0
set d=0
set l=0
set z=
if "%1" == "" (echo %~n0 [FILE] & exit /b 1)
for /f "tokens=1-4" %%a in (%1) do (
echo %%a %%c %%b %%d
goto _BREAK_
)
:_BREAK_
for /f "tokens=1" %%a in ('more +1 %1') do (
if %%a gtr !a! set a=%%a
)
call :length %a% l
for /l %%i in (1,1,%l%) do set z=!z!0
for /f "tokens=1-4" %%a in ('more +1 %1') do (
set a=%z%%%a
set /a d=%%d+1
set %~n0_!a:~-%l%!=%%a %%c %%b !d!
)
for /f "tokens=2 delims==" %%l in ('set %~n0_') do echo %%l
endlocal
goto :EOF
:length
setlocal
set i=0
set t=%~1
if "%t%" == "" endlocal & set %2=0
:_LENGTH_
set t=%t:~1%
set /a i+=1
if not "%t%" == "" goto _LENGTH_
endlocal & set %2=%i%
goto :EOF
|






silverwire
#9400()
[
Batchfile
]
Rating0/0=0.00
バッチで。 e.g. C:\>#276.bat 10 | ** | * * | * * | * * | **** | | | | | X = 7, Y = 5@echo off setlocal enabledelayedexpansion set s= set t= set x=0 set y=0 set dx=-1 set dy=0 if "%~1" == "" (echo usage: %~n0 SIZE >&2 & exit /b 1) set /a x=%~1/2,y=%~1/2 for /l %%j in (1,1,%~1) do ( for /l %%i in (1,1,%~1) do set c[%%i][%%j]=0 ) :_ if !x! lss 1 goto BREAK if !x! gtr %~1 goto BREAK if !y! lss 1 goto BREAK if !y! gtr %~1 goto BREAK if !c[%x%][%y%]! equ 0 ( set c[%x%][%y%]=1 set t=%dx% set dx=%dy% set /a dy=-!t! ) else ( set c[%x%][%y%]=0 set t=%dx% set /a dx=-!dy! set dy=!t! ) set /a x+=%dx%,y+=%dy% cls for /l %%j in (1,1,%~1) do ( set s= for /l %%i in (1,1,%~1) do ( if !c[%%i][%%j]! equ 0 ( set s=!s! ) else ( set s=!s!* ) ) echo ^ !s!^| ) echo X = %x%, Y = %y% ping -n 2 127.0.0.1 > NUL goto _ :BREAK endlocal & echo DEAD END ...Rating0/0=0.00-0+
[ reply ]