批处理脚本(Batch Script)是一种在Windows操作系统中使用命令行界面的脚本语言。尽管它是一种相对古老的编程语言,但仍然有许多实用的功能值得去学习和探索。本文将分享一些批处理脚本编程的技巧,帮助更好地利用这一工具。
如果已经熟悉了基本的命令提示符(cmd.exe)操作或者编写过简单的批处理文件,那么可以跳过这一部分。如果从未尝试过批处理文件编程,欢迎。首先,打开命令提示符,然后输入:
notepad hello.bat
在记事本中输入以下内容:
@echo off
echo Welcome to the Batch Programming World!
关闭记事本并保存文件。回到命令提示符,输入:
hello.bat
然后按回车键。这就是第一个批处理脚本,它会输出上面的消息。
很多时候,需要编写交互式的脚本,从用户那里获取输入,并在需要时进行算术运算。要读取用户输入,可以使用以下语法:
SET /P VarName=The prompt text
例如,要询问用户的名字并显示出来,可以这样做:
@echo off
setlocal
SET /P Name="What is your name?"
echo Welcome %Name%
重要的是,在使用“SET”命令时,不要污染环境变量命名空间。因此,最好在脚本开头使用“setlocal”命令,这样当脚本终止时,环境变量的更改将会恢复。
数字计数在许多场景中都非常有用。它可以用于创建编号的虚拟文件夹、编写需要计数的算法等。在批处理文件中,可以使用以下语法进行计数:
FOR /L %variable IN (start, step, end) DO command [command-parameters]
例如,编写一个创建10个虚拟文件夹的脚本:
@echo off
for /L %%a in (1,1,10) do (
mkdir folder%%a
)
假设有以下文件:
@echo off
setlocal
:repeat
SET /P N="Please enter N for the sigma computation:"
SET /A Result=0
for /L %%i in (1,1,%N%) do (
SET /A Result=Result+%%i
)
echo Sigma(%N%)=%Result%
这是一个计算从1到N的和的脚本。
逐行读取文本文件对于文本扫描和转换非常有用。使用“FOR /F”语法如下:
@echo off
for /f "delims=" %%a in (the-file.txt) DO (
echo Line is: %%a
)
可以这样实现一个非常基础的非空行计数器:
@echo off
setlocal enabledelayedexpansion
if "%1"=="" (
echo Please specify a file name!
goto :eof
)
set /A nlines=0
for /f "delims=" %%a in (%1) DO (
set /A nlines+=1
)
echo Total non-empty lines: %nlines%
“FOR /F”将跳过输入文本文件中的空行。
在批处理脚本语言中,可以进行字符串替换。要实现这一点,需要将字符串放入环境变量中。然后可以使用以下语法:
%VarName:StringToBeMatched=StringToBeReplacedWith%
编写一个交互式脚本,在文件“email.txt”中将单词“books”替换为“ebooks”:
@echo off
setlocal enabledelayedexpansion
if exist new-email.txt del new-email.txt
for /f "delims=" %%a in (email.txt) DO (
set line=%%a
echo !line:books=ebooks! >>new-email.txt
)
这个脚本将进行字符串替换,并生成一个名为“new-email.txt”的新文件。
一个非常有趣的技巧是,可以编写一个脚本,使其在两种或更多语言下都能成功运行。以下是如何编写混合脚本以运行Python和批处理文件的示例:
@echo off
rem This part is ignored by Python
python -x "%~f0" %*
exit /b %errorlevel%
# Anything here is interpreted by Python
import platform
import sys
print("Hello world from Python %s!\n" % platform.python_version())
print("The passed arguments are: %s" % sys.argv[1:])
这是一个批处理脚本,它使用“python -x”开关(跳过第一行)再次调用自己作为Python脚本。
类似于技巧 #5,可以制作一个批处理文件脚本,它也是一个C++程序。以下是如何制作自编译的C++批处理脚本的示例:
/*
2>nul && echo | set /p=
@echo off
setlocal
echo.
:: Self-compiling C++ Batch file!
:: (c) Batchography book - by Elias Bachaalany
set outfile="%~dpn0.exe"
cl %~dpf0 /TP /EHsc /link /out:%outfile% /nologo > nul
if exist %outfile% (
%outfile%
del %outfile%
del "%~dpn0.obj"
) else (
echo Compilation failed!
)
goto :eof
*/
#include
int main() {
printf("Hello world! I was self-compiled!\n\nCheckout the Batchography book!\n");
return 0;
}
这个多语言脚本的缺点是,第一行("/*"是C多行注释的开头)不是有效的命令,它将导致错误,但将错误重定向到nul设备。在退出批处理文件后不久关闭多行注释(用"*/")。
可以执行一个命令,然后将其输出分解成标记。要实现这一点,将使用“FOR /F”语法。
@echo off
for /F "usebackq tokens=3" %%a IN (`reg query "hklm\system\controlset001\control\nls\language" /v Installlanguage`) DO (
set lang_id=%%a
)
:: 0409 English ; 0407 German ; 040C French ; 0C0A Spanish
if "%lang_id%"=="0409" (
echo English detected
) else if "%lang_id%"=="040C" (
echo French detected
) else (
echo Note: Unknown language ID %lang_id%!
)
上面的批处理脚本,过滤出至少有3个标记的行,并只捕获第一个标记。
谁说批处理语言是一种简单的语言?知道可以编写函数(甚至是递归的)吗?要定义一个函数,只需创建一个标签,然后调用它:
@echo off
setlocal
:main
echo Hello!
set /p a=Enter the first number:
set /p b=Enter the second number:
call :add result %a% %b%
echo The result is: %result%
goto :eof
:add
<1=return var> <2=first number> <3=second number>
echo Adding '%2' and '%3'. Returning the result into the variable '%1'
set /a %1=%2+%3
goto :eof