Windows 批处理脚本学习教程

Collected by Clove

第八章:番外篇

标题很奇怪?其实,您可以把它当作一期OVA。

8.1 批量十六进制二进制格式转换

想把数据(流)以十六进制或二进制的形式显示出来?UltraEdit之类的编辑软件一定是首选。即使是要自己亲自转出来,C/C++等语言也会方便的多。如果您跟我一样选择使用批处理来实现的话,那么很好,很有挑战性。

::::::DataFormatConvert.bat:::::
@echo off

:Initialization
set TempFile=temp.tmp
set /a num = 0
set BinaryFormat=Bin
:: 默认为二进制数字0或1显示
set ConvertOption=ConvertToHex
:: 默认为十六进制转换
set ShowProgress=ShowProgressOn
:: 默认为显示转换进度
set BackSpace=[将本文底部评论3中的退格符替换到此处]
:: 退格符

set Source=z%1
:: 添加一个临时字符 z
if %Source:~1,1%z%Source:~-1%=="z" set Source=z%Source:~2,-1%
:: 检查变量参数1的第一个和最后一个字符是否为 "" ,是的话就去掉
set Source=%Source:~1%
:: 去掉临时字符 z
if "%Source%"=="" goto :HelpInformation
if "%Source%"=="/?" goto :HelpInformation
if /i "%Source%"=="/help" goto :HelpInformation
if not exist "%Source%" echo 目标文件不存在 & exit /b 2
:: 检查参数1 [注1]

if /i "%2"=="/Bin" set ConvertOption=ConvertToBin
if /i "%3"=="/Bin" set ConvertOption=ConvertToBin
if /i "%2"=="/Block" set ConvertOption=ConvertToBin & set BinaryFormat=BinBlock
if /i "%3"=="/Block" set ConvertOption=ConvertToBin & set BinaryFormat=BinBlock
if /i "%2"=="/ProgressOff" set ShowProgress=ShowProgressOff
if /i "%3"=="/ProgressOff" set ShowProgress=ShowProgressOff
:: 检查参数2和3 [注2]

for %%i in ("%Source%") do (
set SourceDrivePathName=%%~dpni
set FileSize=%%~zi
)
:: 获得源文件的 驱动器号+路径+标题名 ,以及文件大小。 d - drive, p - path, n - name, z - size
if "%FileSize%"=="0" echo 目标文件为空 & exit /b 3
del %TempFile% >nul 2>nul
fsutil file createnew %TempFile% %FileSize% >nul
:: 创建一个大小与源文件一样的空白文件,该文件里的所有字节均为0x00

goto :%ConvertOption%

:ConvertToHex
:: 十六进制转换
setlocal EnableDelayedExpansion
set OutputFile="%SourceDrivePathName%.Hex.txt"
echo 文件 %Source% 的十六进制格式:>%OutputFile%
echo. & echo 正在转换为十六进制...

for /f "skip=1 tokens=1,3" %%i in ('fc /b %TempFile% "%Source%"') do (
set index=0x%%i
set index=!index:~0,-1!
set /a offset = !index! - !num!

for /l %%n in (1,1,!offset!) do (
set /p=00<nul>>%OutputFile%
set /a num += 1
)
set /p=%%j<nul>>%OutputFile%
set /a num += 1
call :%ShowProgress% !num!
)
:: 通过与大小相同内容空白的文件进行二进制对比,获得源文件的十六进制码 [注3]
endlocal
goto :ExitSuccess

:ConvertToBin
setlocal EnableDelayedExpansion
set OutputFile="%SourceDrivePathName%.%BinaryFormat%.txt"
echo 文件 %Source% 的二进制格式:>%OutputFile%
echo. & echo 正在转换为二进制...

for /f "skip=1 tokens=1,3" %%i in ('fc /b %TempFile% "%Source%"') do (
set index=0x%%i
set index=!index:~0,-1!
set /a offset = !index! - !num!

for /l %%n in (1,1,!offset!) do (
call :HexTo%BinaryFormat% 0
call :HexTo%BinaryFormat% 0
set /a num += 1
)
set HexData=%%j
call :HexTo%BinaryFormat% !HexData:~0,1!
call :HexTo%BinaryFormat% !HexData:~1,1!
set /a num += 1
call :%ShowProgress% !num!
)
endlocal
goto :ExitSuccess

:HexToBin
:: 函数: HexToBin 用途: 以0或1的形式显示
if %1==0 set /p=0000<nul>>%OutputFile%
if %1==1 set /p=0001<nul>>%OutputFile%
if %1==2 set /p=0010<nul>>%OutputFile%
if %1==3 set /p=0011<nul>>%OutputFile%
if %1==4 set /p=0100<nul>>%OutputFile%
if %1==5 set /p=0101<nul>>%OutputFile%
if %1==6 set /p=0110<nul>>%OutputFile%
if %1==7 set /p=0111<nul>>%OutputFile%
if %1==8 set /p=1000<nul>>%OutputFile%
if %1==9 set /p=1001<nul>>%OutputFile%
if %1==A set /p=1010<nul>>%OutputFile%
if %1==B set /p=1011<nul>>%OutputFile%
if %1==C set /p=1100<nul>>%OutputFile%
if %1==D set /p=1101<nul>>%OutputFile%
if %1==E set /p=1110<nul>>%OutputFile%
if %1==F set /p=1111<nul>>%OutputFile%
goto :EOF

:HexToBinBlock
:: 函数: HexToBinBlock 用途: 以 或■的形式显示[注3]
if %1==0 set /p=    <nul>>%OutputFile%
if %1==1 set /p=   ■<nul>>%OutputFile%
if %1==2 set /p=  ■ <nul>>%OutputFile%
if %1==3 set /p=  ■■<nul>>%OutputFile%
if %1==4 set /p= ■  <nul>>%OutputFile%
if %1==5 set /p= ■ ■<nul>>%OutputFile%
if %1==6 set /p= ■■ <nul>>%OutputFile%
if %1==7 set /p= ■■■<nul>>%OutputFile%
if %1==8 set /p=■   <nul>>%OutputFile%
if %1==9 set /p=■  ■<nul>>%OutputFile%
if %1==A set /p=■ ■ <nul>>%OutputFile%
if %1==B set /p=■ ■■<nul>>%OutputFile%
if %1==C set /p=■■  <nul>>%OutputFile%
if %1==D set /p=■■ ■<nul>>%OutputFile%
if %1==E set /p=■■■ <nul>>%OutputFile%
if %1==F set /p=■■■■<nul>>%OutputFile%
goto :EOF

:ShowProgressOn
:: 函数: ShowProgressOn 用途: 显示转换进度
set /a mod = %1 %% 50
if %mod% equ 0 (
set /a percent = %1 * 100 / %FileSize%
set /p=%BackSpace%%BackSpace%%BackSpace%<nul
set /p=!percent!%%<nul
)
goto :EOF

:ShowProgressOff
:: 函数: ShowProgressOff 用途: 不显示转换进度
goto :EOF

:HelpInformation
:: 该批处理的帮助信息
echo 将文件转换为十六进制或二进制的格式。
echo.
echo DataFormatConvert source [/Hex ^| /Bin ^| /Block] [/ProgressOn ^| /ProgressOff]
echo.
echo source 指定要转换的文件。
echo /Hex 表示转换为十六进制格式(默认)。
echo /Bin 表示转换为二进制格式。
echo /Block 表示转换为二进制格式并以方块的形式显示。
echo /ProgressOn 显示转换进度(默认)。
echo /ProgressOff 关闭显示进度。
exit /b 1

:ExitSuccess
:: 成功完成并退出
del %TempFile% >nul
set /p=%BackSpace%%BackSpace%%BackSpace%%BackSpace%<nul
echo 转换完成!
exit /b 0
::::::::::::::::::::::::::::::::

注1 exit 的参数 /b ,可以退出当前批处理脚本而不退出调用它的 CMD.EXE。如果从一个批处理脚本外执行,则会退出 CMD.EXE 。exit 的第二个参数 exitCode 是一个数字号码,如果使用了参数 /b ,这个数字号码将成为该批处理退出的 ErrorLevel 。如果退出 CMD.EXE ,则用那个数字设置过程退出代码。

注2 看到该批处理这些可使用的参数,您可能已经发现了,该批处理可以作为一条外部命令来使用,如果您把它放到 %SystemRoot%\system32 或 %SystemRoot% 路径下的话。默认情况下,%SystemRoot%\system32 和 %SystemRoot% 都是环境变量 PATH 的值之一(在 我的电脑->属性->高级->环境变量 中可以查看并设置相关环境变量)。

注3 源文件通过与其大小相同内容全为0x00的文件进行对比后,可以将源文件中所有与0x00不同的字节内容以十六进制码的形式表达出来。同时,还能得到每个不同字节所在的字节数位置,通过这个也便确定了源文件中0x00的内容。

正如注2中所说的,如果该批处理被放到了环境变量 PATH 中的路径中,则它可以作为外部命令来为您工作。


DataFormatConvert 的执行示意

十六进制或二进制转换成功的文件将被写到与源文件相同的路径中。


经DataFormatConvert 十六进制转换后的文件
对于计算机而言,十六进制码(或者说0和1)才能表达出它们自己的想法,尽管这些对我们来说犹如天书一般。

========================================朴实的分割线========================================

8.2 别挤,自启动的排队来

被放入到自启动项里的程序,从某种意义上来说,在被开启的时候确实简化了用户的操作。然而,在开机后众多的程序就像春运时期挤火车一样的蜂拥而上,这并不是我们所期望的。请不要问我为什么给这个批处理起了个如此无理的名称,所有放在 C:\WINDOWS 下的批处理我都会以小写字母 z 打头,方便管理。

::::::::::zLauncher.bat:::::::::
@echo off
setlocal enabledelayedexpansion
title Launching...
set /a ShortDelay = 6
set BackSpace=[将本文底部评论3中的退格符替换到此处]

set /p choice=LaunchOptions:
if not "%choice%"=="" goto :CustomLaunch

:BasicLaunch
call :LaunchItem1
call :LaunchItem2
call :LaunchItem3
call :LaunchItem4
call :LaunchItem5
goto :EOF

:CustomLaunch
for /l %%i in (0 1 9) do (
set "choice_=!choice:~%%i,1!"
if "!choice_!"=="" echo All Launched! & goto :EOF
if !choice_! gtr 9 echo Unknown Define & goto :EOF
if !choice_! lss 0 echo Unknown Define & goto :EOF
call :LaunchItem!choice_!
)

:LaunchItem1
start "OE" "C:\Program Files\Outlook Express\msimn.exe"
call :IsItemLaunchedSuccessful OE
goto :EOF
:LaunchItem2
start "Skype" "D:\Program Files\Skype\Phone\Skype.exe" /nosplash /minimized
call :IsItemLaunchedSuccessful Skype
goto :EOF
:LaunchItem3
Start "QQ" "D:\Program Files\Tencent\QQ\QQ.exe"
call :IsItemLaunchedSuccessful QQ
goto :EOF
:LaunchItem4
start "BaiduHi" /min "D:\Program Files\baidu\Baidu Hi\BaiduHi.exe"
call :IsItemLaunchedSuccessful BaiduHi
goto :EOF
:LaunchItem5
start "Thunder" /min "D:\Program Files\Thunder Network\Thunder\Thunder.exe"
call :IsItemLaunchedSuccessful Thunder
goto :EOF
:LaunchItem6
start "Tudou" /min "D:\Program Files\Tudou\iTudou\iTudou.exe"
call :IsItemLaunchedSuccessful Tudou
goto :EOF
:LaunchItem7
start "MSN" /min "C:\Program Files\MSN Messenger\msnmsgr.exe"
call :IsItemLaunchedSuccessful MSN
goto :EOF

:IsItemLaunchedSuccessful
set /p =Launching %1<nul & title Launching %1
if ERRORLEVEL 0 (
for /l %%i in (1,1,4) do (
ping -n %ShortDelay% 127.1>nul
set /p =.<nul
)
)
for /l %%i in (1,1,32) do set /p =%BackSpace%<nul
echo %1 Launched
title %1 Launched
ping -n %ShortDelay% 127.1>nul
goto :EOF
::::::::::::::::::::::::::::::::

看得出来,这是一个科技含量很低的批处理,仅仅是在 start 每个程序之间将其挂起一段时间来避免众多程序同时启动所带来的负荷。当然,为了使它能够发挥作用,您得亲自配置它所要启动的程序,以及程序所在的路径才行。

Collected by Clove--Mail to Me

Windows 批处理脚本学习教程