Windows 批处理文件有哪些鲜为人知但重要且有用的功能?
指导方针:
- 每个答案一个功能
- 提供特性的简短描述和示例,而不仅仅是文档链接
- 限制对本机功能的回答,即不需要额外的软件,如Windows 资源工具包
澄清:我们在这里指的是由 cmd.exe 处理的脚本,这是 WinNT 变体的默认设置。
(另请参阅:Windows 批处理文件:.bat 与 .cmd?)
Windows 批处理文件有哪些鲜为人知但重要且有用的功能?
指导方针:
澄清:我们在这里指的是由 cmd.exe 处理的脚本,这是 WinNT 变体的默认设置。
(另请参阅:Windows 批处理文件:.bat 与 .cmd?)
续行:
call C:\WINDOWS\system32\ntbackup.exe ^
backup ^
/V:yes ^
/R:no ^
/RS:no ^
/HC:off ^
/M normal ^
/L:s ^
@daily.bks ^
/F daily.bkf
PUSHD path
将您带到path指定的目录。
POPD
带您回到您“推送”的目录。
不确定这在批处理文件中会有多大用处,但在命令提示符下使用它是一个非常方便的命令:
C:\some_directory> start .
这将在“some_directory”文件夹中打开 Windows 资源管理器。
我发现这是一个很好的节省时间的方法。
我一直发现很难阅读每行上用关键字标记的注释:
REM blah blah blah
更容易阅读:
:: blah blah blah
可变子串:
> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
FOR命令!虽然我讨厌编写批处理文件,但我很感激它。
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k
将解析 myfile.txt 中的每一行,忽略以分号开头的行,将每行的第二个和第三个标记传递给 for 正文,标记由逗号和/或空格分隔。请注意 for body 语句引用 %i 来获取第二个标记,%j 获取第三个标记,以及 %k 获取第三个之后的所有剩余标记。
您还可以使用它来迭代目录、目录内容等...
我没有在脚本中乱扔 REM 或 :: 行,而是在每个脚本的顶部执行以下操作:
@echo OFF
goto :START
Description of the script.
Usage:
myscript -parm1|parm2 > result.txt
:START
请注意如何使用管道和重定向字符而不转义它们。
脚本所在的路径(带驱动器):~dp0
set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
%~dp0 部分已经提到过,但实际上还有更多内容:~ 之后的字符定义了提取的信息。
没有字母导致返回补丁文件名
d - 返回驱动器号
p - 返回路径
s - 返回短路径
x - 返回文件扩展名
所以如果你从 c:\Temp 执行下面的脚本 test.bat \long dir name\ 文件夹,
@echo off
echo %0
echo %~d0
echo %~p0
echo %~dp0
echo %~x0
echo %~s0
echo %~sp0
你得到以下输出
test c: \Temp\long dir name\ c:\Temp\long dir name\ .bat c:\Temp\LONGDI~1\test.bat \Temp\LONGDI~1\
如果像在
test c:\temp\mysrc\test.cpp
中一样将参数传递到您的脚本中,则可以使用 %1 变量进行相同的操作。
但是 %0 的扩展结果取决于位置!
在批处理的“顶层”,它扩展为当前批处理文件名。
在函数(调用)中,它扩展为函数名。
@echo off
echo %0
call :test
goto :eof
:test
echo %0
echo %~0
echo %~n0
输出是(批处理文件以 myBatch.bat 开头)
myBatch.bat
:test
:test
myBatch
通过使用 CALL、EXIT /B、SETLOCAL 和 ENDLOCAL,您可以使用局部变量实现子例程。
例子:
@echo off
set x=xxxxx
call :sub 10
echo %x%
exit /b
:sub
setlocal
set /a x=%1 + 1
echo %x%
endlocal
exit /b
这将打印
11
xxxxx
即使 :sub 修改了 x。
等待 N 秒的诡计(不是 cmd.exe 的一部分,但不是额外的软件,因为它与 Windows 一起提供),请参阅 ping 行。您需要 N+1 次 ping,因为第一次 ping 会立即发出。
echo %time%
call :waitfor 5
echo %time%
goto :eof
:waitfor
setlocal
set /a "t = %1 + 1"
>nul ping 127.0.0.1 -n %t%
endlocal
goto :eof
逃离“管道”:
echo ^| ^< ^> ^& ^\ ^^
能够运行命令并处理输出(如 bash 中的 '$()' 的反引号)。
for /f %i in ('dir /on /b *.jpg') do echo --^> %i
如果文件名中有空格,请使用:
for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %i
创建一个空文件:
> copy nul filename.ext
隐藏命令重定向到 >nul 2>&1 的所有输出。
例如,即使您重定向到 >nul,某些命令行程序也会显示输出。但是,如果您像下面的行那样重定向输出,则所有输出都将被抑制。
PSKILL NOTEPAD >nul 2>&1
编辑:有关其工作原理的说明,请参阅忽略命令的输出。
PAUSE
停止执行并显示以下提示:
按任意键继续 。. .
如果您想通过在 Windows 资源管理器中双击它来运行批处理并希望实际查看输出而不仅仅是命令窗口的闪烁,这很有用。
相当于 bash(和其他 shell)
echo -n Hello # or
echo Hello\\c
它输出 " Hello
" 没有尾随换行符。执行此操作的 cmd hack:
<nul set /p any-variable-name=Hello
set /p
是一种提示用户输入的方式。它发出给定的字符串,然后等待(在同一行,即没有 CRLF),让用户输入响应。
<nul
只需将空响应传递给set /p
命令,因此最终结果是发出的提示字符串。(由于空响应,使用的变量保持不变。)
问题是:不可能输出前导等号,并且在 Vista 上会删除前导空白字符,但在 XP 上不会。
设置环境变量时搜索替换:
> @set fname=%date:/=%
...从日期中删除“/”以用于带时间戳的文件名。
还有子字符串...
> @set dayofweek=%fname:~0,3%
整数运算:
> SET /A result=10/3 + 1
4
命令分隔符:
cls & dir
copy a b && echo Success
copy a b || echo Failure
在第 2 行,&& 之后的命令仅在第一个命令成功时运行。
在第 3 行,|| 之后的命令 仅在第一个命令失败时运行。
输出一个空行:
echo.
您可以链接 if 语句以获得类似短路布尔值“和”的效果。
if foo if bar baz
快速将 Unicode 文本文件 (16bit/char) 转换为 ASCII DOS 文件 (8bit/char)。
C:\> type unicodeencoded.txt > dosencoded.txt
作为奖励,如果可能的话,字符被正确映射。
if 块结构:
if "%VS90COMNTOOLS%"=="" (
echo: Visual Studio 2008 is not installed
exit /b
)
变量的延迟扩展(为了很好的措施,加入了子字符串):
@echo off
setlocal enableextensions enabledelayedexpansion
set full=/u01/users/pax
:loop1
if not "!full:~-1!" == "/" (
set full2=!full:~-1!!full2!
set full=!full:~,-1!
goto :loop1
)
echo !full!
endlocal
不提供太多功能,但您可以将 title 命令用于多种用途,例如在任务栏中的长脚本上提供状态,或仅用于增强用户反馈。
@title Searching for ...
:: processing search
@title preparing search results
:: data processing
字符串减法示例date
并time
获取名为“YYYY-MM-DD HH:MM:SS.txt”的文件
echo test > "%date:~0,4%-%date:~5,2%-%date:~8,2% %time:~0,2%_%time:~3,2%_%time:~6,2%.txt"
我color
通过更改文本和背景的颜色来指示我的脚本是否成功、失败或需要一些输入。当您的视野范围内有一些机器但距离很远时,这真的很有帮助
颜色 XY
其中 X 和 Y 是从0
to的十六进制值F
,其中 X - 背景,Y - 文本,当 X = Y 颜色不会改变。
颜色 Z
将文本颜色更改为“Z”并设置黑色背景,“颜色 0”将不起作用
颜色名称调用
颜色 ?
手边没有编辑器,需要创建批处理文件?
copy con test.bat
只需输入命令,按回车换行。按 Ctrl-Z 和 Enter 关闭文件。
使用空格和转义字符完全控制输出。:
echo. ^<resourceDir^>/%basedir%/resources^</resourceDir^>
TheSoftwareJedi 已经提到了 for 命令,但我将再次提及它,因为它非常强大。
以下以 YYYYMMDD 格式输出当前日期,我在生成备份目录时使用它。
for /f "tokens=2-4 delims=/- " %a in ('DATE/T') do echo %c%b%a
您可以稍后使用 call 来评估名称,从而获得一些有用的属性。
call set SomeEnvVariable_%extension%=%%%somevalue%%%
使用 call 设置名称依赖于其他变量的变量。如果与一些变量命名规则一起使用,您可以通过使用谨慎的命名规则来模拟数组或字典等数据集合。somevalue 周围的三个 % 是这样,因此它将在调用之后和调用 set 之前评估为一个由单个 % 包围的变量名。这意味着连续两个 % 转义为单个 % 字符,然后它将再次扩展它,因此 somevalue 实际上是一个名称指针。
call set TempVar=%%SomeEnvVariable_%extension%%%
将它与临时变量一起使用来检索值,然后您可以在逻辑中使用它。这在与延迟变量扩展结合使用时最有用。
要正确使用此方法,需要启用延迟变量扩展。因为默认情况下它是关闭的,所以最好通过将其作为第一条指令之一在脚本中启用它:
setlocal EnableDelayedExpansion
在路径上搜索可执行文件(或其他类似路径的字符串,如有必要):
c:\> for %i in (cmd.exe) do @echo. %~$PATH:i
C:\WINDOWS\system32\cmd.exe
c:\> for %i in (python.exe) do @echo. %~$PATH:i
C:\Python25\python.exe
c:\>
关于使用::
而不是REM
评论:小心!::
是 CALL 标签的特例,其作用类似于注释。当在括号内使用时,例如在 FOR 或 IF 循环中,函数将过早退出。调试非常令人沮丧!
有关完整说明,请参阅http://www.ss64.com/nt/rem.html。
(作为新的答案而不是对上面第一次提到的评论添加,因为我还不值得:0)
现在很多人使用 GOTO :EOF 来终止他们的批处理文件,但你也可以使用 EXIT /B 来达到这个目的。
使用 EXIT /B 的好处是您可以在 EXIT /B 之后添加一个错误级别,它将以该错误级别退出。
仍然为 ENDLOCAL 使用的行解析局部变量。这允许使用以下技巧:
ENDLOCAL & SET MYGLOBAL=%SOMELOCAL% & SET MYOTHERGLOBAL=%SOMEOTHERLOCAL%
这是将结果传输到调用上下文的有用方法。具体来说,一旦 ENDLOCAL 完成,%SOMELOCAL% 就会超出范围,但到那时 %SOMELOCAL% 已经展开,因此 MYGLOBAL 在调用上下文中分配有局部变量。
出于同样的原因,如果您决定这样做:
ENDLOCAL & SET MYLOCAL=%MYLOCAL%
您会发现您的新 MYLOCAL 变量现在实际上是作为常规环境变量出现的,而不是您可能想要的本地化变量。
子程序(输出 42):
@echo off
call :answer 42
goto :eof
:do_something
echo %1
goto :eof
和返回值的子程序(输出 0、1、2 等):
@echo off
setlocal enableextensions enabledelayedexpansion
call :seq_init seq1
:loop1
if not %seq1%== 10 (
call :seq_next seq1
echo !seq1!
goto :loop1
)
endlocal
goto :eof
:seq_init
set /a "%1 = -1"
goto :eof
:seq_next
set /a "seq_next_tmp1 = %1"
set /a "%1 = %seq_next_tmp1% + 1"
set seq_next_tmp1=
goto :eof
cmd.exe 中的快速编辑模式是我的最爱。这有点离题,但是当与命令 shell 交互时,它可以成为救命稻草。不,我不是在夸大其词——在你死之前你只会看到一定次数的caret-capitol-v ;你看到的越多,你死得越快。
(您也可以从 UI 中进行设置,这可能是更好的方法。请参阅注释以获取说明。还有一个不错的单行脚本也可以执行此操作。)
现在,要复制,只需左键单击并拖动以选择并右键单击以复制。要粘贴,只需右键单击。
没有了^V^V^V^V^V^V^V^V^V^V^V^V^V^V!!!
废话,我想我刚刚杀了人。对不起!
Call Set - 将环境变量扩展几个级别。
在http://ss64.com/nt/call.html#advanced from answer to another SO question找到这个 在for循环中初始化的批处理文件变量
set VarName=Param
set Param=This
call set Answer=%%%Varname%%%
Echo %Answer%
给
set VarName=Param
set Param=This
call set Answer=%Param%
Echo This
This
“删除目录”上的子目录选项:
rd /s /q junk
SHIFT
这是一种迭代传递给命令行脚本(或子例程)的可变数量参数的方法。在最简单的用法中,它将 %2 转换为 %1,将 %3 转换为 %2,依此类推。(您也可以将参数传递给 SHIFT 以跳过多个参数。)这使命令“具有破坏性”(即 %1 永远消失),但它允许您避免硬编码最大数量的受支持参数。
这是一个处理命令行参数的简短示例:
:ParseArgs
if "%1"=="" (
goto :DoneParsingArgs
)
rem ... do something with %1 ...
shift
goto :ParseArgs
:DoneParsingArgs
rem ...
将输出重定向到控制台,即使批处理的输出已经通过> con
语法重定向到文件。
示例:foo.cmd:
echo a
echo b > con
来电:
foo.cmd > output.txt
这将导致"a"
进入output.txt
控制台"b"
。
您可以使用 errorlevel 检查给定程序是否在您的批处理文件将运行的系统(当前目录或路径)上可用。为此,您正在测试的程序必须运行、退出并设置退出代码。在我使用的示例中 -? 作为 myExe 的 arg,大多数 CLI 程序都有类似的 arg,例如 -h、--help、-v 等……这确保它简单地运行并退出离开或设置错误级别 0
myExe -? >nul 2>&1
Set errCode=%errorlevel%
@if %errCode% EQU 0 (
echo myExe -? does not return an error (exists)
) ELSE (
echo myExe -? returns an error (does not exist)
)
是的,您可以直接测试 errorlevel 而不是将其分配给 errCode 但这样您就可以在测试和条件之间使用命令,并根据需要重复测试条件。
带有数字变量的循环的正确格式是
for /l %%i in (startNumber, counter, endNumber) do echo %%i
要从脚本内部解析标准输入,您需要使用 FOR 和 FIND 命令的技巧:
for /f "tokens=*" %%g in ('find /V ""') do (
:: do what you want with %%g
echo %%g
)
CHOICE命令提示用户选择多个选项之一(通过单个按键)
@echo off
echo Please choose one of the following options
echo 1. Apple
echo 2. Orange
echo 3. Pizza
echo a, b, c. Something else
choice /c:123abc /m "Answer?"
set ChoiceLevel=%ErrorLevel%
echo Choice was: %ChoiceLevel%
%ChoiceLevel%
将是选择的第 n 个选项(在上面的示例中,b=5
)。
更多详情,请访问SS64.com上的CHOICE参考页面。
当您想在分支之间复制文件时,一个方便的技巧:
C:\src\branch1\mydir\mydir2\mydir3\mydir4>xcopy %cd:branch1=branch2%\foo*
Overwrite C:\src\branch1\mydir\mydir2\mydir3\mydir4\foo.txt (Yes/No/All)? y
C:\src\branch2\mydir\mydir2\mydir3\mydir4\foo.txt
这同时使用 %cd% 环境变量和环境变量替换。
获取当前日期、月份和年份(与区域无关):
for /f "tokens=1-4 delims=/-. " %%i in ('date /t') do (call :set_date %%i %%j %%k %%l)
goto :end_set_date
:set_date
if ("%1:~0,1%" gtr "9") shift
for /f "skip=1 tokens=2-4 delims=(-)" %%m in ('echo,^|date') do (set %%m=%1&set %%n=%2&set %%o=%3)
goto :eof
:end_set_date
echo day in 'DD' format is %dd%; month in 'MM' format is %mm%; year in 'YYYY' format is %yy%
我发现您可以轻松地将命令的输出重定向到文件非常有用:
DIR *.txt > tmp.txt
DIR *.exe >> tmp.txt
单箭头创建或覆盖文件,双箭头附加到它。现在我可以在我的文本编辑器中打开 tmp.txt 并做各种好事。
/c cmd.exe 本身的参数,告诉它运行然后执行这些命令。
我曾经发现自己经常这样做:
win+r , cmd返回, ping google.com返回
但现在我只是这样做:
win+r , cmd /c ping google.com返回
快多了。如果您使用 pstools 并且想要使用 psexec 在远程计算机上执行某些命令行功能,这也很有帮助。
编辑: /k工作相同,但保持提示打开。这可能会更频繁地派上用场。
使用&::
.
:: This is my batch file which does stuff.
copy thisstuff thatstuff &:: We need to make a backup in case we screw up!
:: ... do lots of other stuff
这是如何运作的?这是一个丑陋的黑客。&
是大致近似于;
UNIX shell的命令分隔符。这::
是另一个有点模仿REM
声明的丑陋黑客。最终结果是您执行命令,然后执行无操作命令,从而近似于注释。
这并非在所有情况下都有效,但它通常足以成为一个有用的黑客。
对于它的价值,这是一个很好的 Windows CMD 或批处理文件的在线参考。我从中学到了一些我不知道的东西。
forfiles非常有用,例如,递归删除所有超过两天的文件
forfiles /D -2 /P "C:\Temp" /S /C "cmd /c del @path"
Findstr 支持正则表达式:
findstr "^[0-9].*" c:\windows\system32\drivers\etc\hosts
使用 pushd 到 UNC 路径将创建一个临时驱动器映射(从 Z 开始并向后工作以查找下一个可用字母)并将您置于该驱动器和路径中。当您 popd 或退出命令提示符时,临时映射就消失了。
C:\>pushd \\yourmom\jukebox
Z:\>pushd \\yourmom\business
Y:\>
此外,与其说是批处理提示,不如说是命令行环境提示,但是当您在命令行中使用 pushd 和 popd 以及网络共享时,使用 $+ 修改提示很有用(显示 pushd 堆栈深度)和$M(显示网络共享路径)。
C:\utils>prompt $+$m$p$g
C:\utils>pushd m:
+\\yourmom\pub M:\>pushd c:\
++c:\>pushd
M:\
C:\utils
++c:\>popd
+\\yourmom\pub M:\>popd
C:\utils>
使用管道“|”在文件夹中的文件中查找字符串 命令:
dir /b *.* | findstr /f:/ "thepattern"
批处理文件中的数组。
设置一个值:
set count=1
set var%count%=42
在命令行中提取一个值:
call echo %var%count%%
在批处理文件中提取一个值:
call echo %%var%count%%%
注意额外的扫射 % 符号。
该技术可能看起来有点毛茸茸,但它非常有用。如我们所解释的,上面将打印var1的内容(即 42)。如果我们想将其他变量设置为var1中的值,我们也可以用set替换echo命令。这意味着以下是命令行中的有效分配:
call set x=%var%count%%
然后查看va1的值:
echo %x%
Doskey 宏。
我早就失去了这个参考,但我仍然认为这是一个好主意,值得分享。
我们可以将批处理文件和 doskey 脚本合并到一个文件中。这可能看起来有点过于聪明,但它确实有效。
;= @echo off
;= rem Call DOSKEY and use this file as the macrofile
;= %SystemRoot%\system32\doskey /listsize=1000 /macrofile=%0%
;= rem In batch mode, jump to the end of the file
;= goto end
;= Doskey aliases
h=doskey /history
;= File listing enhancements
ls=dir /x $*
;= Directory navigation
up=cd ..
pd=pushd
;= :end
;= rem ******************************************************************
;= rem * EOF - Don't remove the following line. It clears out the ';'
;= rem * macro. Were using it because there is no support for comments
;= rem * in a DOSKEY macro file.
;= rem ******************************************************************
;=
它通过定义一个假的 doskey 宏';'来工作 当它被解释为批处理文件时,它会被优雅地(或静默地)忽略。
我已经缩短了这里列出的版本,如果你想要更多,去这里。
这里如何通过扫描给定目录来构建 CLASSPATH。
setlocal ENABLEDELAYEDEXPANSION
if defined CLASSPATH (set CLASSPATH=%CLASSPATH%;.) else (set CLASSPATH=.)
FOR /R .\lib %%G IN (*.jar) DO set CLASSPATH=!CLASSPATH!;%%G
Echo The Classpath definition is %CLASSPATH%
适用于 XP(或更好)。使用 W2K,您需要使用几个 BAT 文件来获得相同的结果(请参阅在类路径定义中包含所有 jar)。
1.6 不需要它,因为您可以直接在 CLASSPATH 中指定通配符(例如 -cp ".\lib*")。
一行中的多个命令,在许多情况下都很有用:
& 用于组合两个命令,先执行 command1,然后执行 command2
&& 条件组合,如果 command1 成功执行,则执行 command2
¦¦ command2 只有在 command1 未成功完成时才执行。
例子:
:: ** Edit the most recent .TXT file and exit, useful in a .CMD / .BAT **
FOR /F %%I IN ('DIR *.TXT /B /O:-N') DO NOTEPAD %%I & EXIT
:: ** If exist any .TXT file, display the list in NOTEPAD, if not it
:: ** exits without any error (note the && and the 2> error redirection)
DIR *.TXT > TXT.LST 2> NUL && NOTEPAD TXT.LST
允许您根据环境变量更改目录,而无需指定 '%' 指令。如果指定的变量不存在,则尝试目录名称。
@if defined %1 (call cd "%%%1%%") else (call cd %1)
我会说 DEBUG.EXE 是批处理文件的一个非常有用且未充分利用的功能。
DEBUG 命令允许您...
简而言之,这个工具非常强大。这些天可能不再使用它,但是从批处理脚本调用和控制此功能的功能为批处理脚本增加了惊人的功能。
注意:据我所知,Microsoft 已从 64 位版本的 Windows Xp 和 Vista 中删除了此命令,并打算将其从 Windows 7 中完全删除。
从文件中设置环境变量SET /P
SET /P SVNVERSION=<ver.tmp
将错误级别设置为您想要的任何数字的方法:
CMD /C 退出号
goto :eof 粘贴板
我在脚本末尾添加“goto :eof”作为代码片段的方便空间。这样我就可以快速复制/粘贴到该区域,而无需评论/取消评论。
goto :eof
:: code scraps
call this.bat
call that.bat
set TS=%DATE:~10%%DATE:~4,2%%DATE:~7,2%-%TIME:~0,2%%TIME:~3,2%%TIME:~6%%
for /R C:\temp\ %%G in (*.bak) DO del %%G
隐藏交互式批处理脚本的输入:
@echo off
echo hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5>in.com
set /p secret_password="Enter password:"<nul
for /f "tokens=*" %%i in ('in.com') do (set secret_password=%%i)
del in.com
列出所有驱动器:
fsutil fsinfo drives
创建并开始编辑新文件
copy con new.txt
This is the contents of my file
^Z
Ctrl+Z 发送 ASCII EOF 字符。这就像 bash 中的 heredocs:
cat <<EOF > new.txt
This is the contents of my file
EOF
删除周围的报价。
for /f "useback tokens=*" %%a in ('%str%') do set str=%%~a
我最近必须编写一个由 VS prebuild 事件调用的批处理文件,并且我想将项目目录作为参数传递。在批处理文件中,我需要将路径与嵌套的子文件夹名称连接起来,但首先需要删除周围的引号。
错误保释。
IF "%errorlevel%" NEQ "0" (
echo "ERROR: Something broke. Bailing out."
exit /B 1
)
符号链接:
mklink /d directorylink ..\realdirectory
mklink filelink realfile
该命令在 Windows Server 2008 和更新版本(包括 Vista 和 Windows 7)上是本机的。(它也包含在某些 Windows 资源工具包中。)
使用副本附加文件:
copy file1.txt+file2.txt+file3.txt append.txt
此外,要将所有 CLI 参数设置为单个变量:
SET MSG=%*
这将获取以空格分隔的每个单词(或符号)并将其保存到单个批处理文件变量中。从技术上讲,每个参数是 %1、%2、$3 等,但是这个 SET 命令使用通配符来引用标准输入中的每个参数。
批处理文件:
@SET MSG=%*
@echo %MSG%
命令行:
C:\test>test.bat Hello World!
Hello World!
递归搜索目录树中的字符串:
findstr /S /C:"string literal" *.*
您还可以使用正则表达式:
findstr /S /R "^ERROR" *.log
递归文件搜索:
dir /S myfile.txt
与上面非常相似,使用 CALL、EXIT /B、SETLOCAL 和 ENDLOCAL,您可以使用局部变量和返回值来实现函数。
例子:
@echo off
set x=xxxxx
call :fun 10
echo "%x%"
echo "%y%"
exit /b
:fun
setlocal
set /a y=%1 + 1
endlocal & set x=%y%
exit /b
这将打印:
"11"
""
y 变量永远不会离开本地作用域,但是由于 CMD 一次解析一行的方式,您可以将值提取到父作用域中的 x 变量中。
对于带有数字计数器的循环(输出 1 到 10):
for /l %i in (1,1,10) do echo %i
这是我用来连续运行 My Nant Build 脚本的一个技巧,而不必一遍又一遍地单击批处理文件。
:CODELINE
NANT.EXE -buildfile:alltargets.build -l:build.log build.product
@pause
GOTO :CODELINE
将会发生的是,在您的解决方案完成构建后,它将被暂停。然后,如果您按任意键,它将再次重新运行构建脚本。我必须说非常方便。
HELP
当使用不同的操作系统版本时,了解本机可用的命令很重要。在命令提示符下键入 HELP 会显示可用的命令,并简要说明它们的作用。
cmd.exe /?
这将列出用于启动命令提示符的所有命令行参数以及更改系统范围行为的注册表调整。
在脚本中使用命令扩展shell 选项时,强烈建议您在脚本开头执行以下技巧。
-- 从http://www.ss64.com/nt/setlocal.html粘贴的信息
如果给定一个参数,SETLOCAL 将设置一个 ERRORLEVEL。如果给出两个有效参数之一,则它将为零,否则为零。
您可以在批处理文件中使用它来确定命令扩展是否可用,使用以下技术:
VERIFY errors 2>nul
SETLOCAL ENABLEEXTENSIONS
IF ERRORLEVEL 1 echo Unable to enable extensions
这是因为“验证错误”将 ERRORLEVEL 设置为 1,然后如果扩展不可用(例如,如果脚本在 command.com 下运行),SETLOCAL 将无法重置 ERRORLEVEL 值
如果命令扩展被永久禁用,则 SETLOCAL ENABLEEXTENSIONS 将不会恢复它们。
获取环境变量总大小的一个非常古老的(约 1990 年)技巧:
set > test
dir test
del test
此批处理文件既可用于简单文件,也可用于目录作为命令行参数(您可以按任何顺序混合它们)。循环在任何指定的文件上运行命令(在本例中为“echo”),如果参数是目录,它会在其中的每个文件上递归地运行命令。
@echo off
for /f "delims=" %%f in ('dir %* /a-d /b /s') do echo %%f
IF 命令!没有它,我的批处理文件就是垃圾!
@echo off
IF exist %windir%\system32\iexplore.exe goto end
echo Hmm... it seems you do not have Internet Explorer.
echo Great! You seem to understand ;)
:end
echo Hmm... You have Internet Explorer.
echo That is bad :)
我真的很喜欢这个Windows XP 命令参考,以及顶部的语法链接;它涵盖了其他答案中已经发现的许多提示和技巧。
还有 EDLIN 命令。虽然它可能是一个曾经用于基于行的文本编辑的老混蛋工具,但它可以从命令行控制这一事实使得它对批处理脚本非常有用,主要是因为,就像您使用 EDLIN 的任何其他情况一样,它是唯一可用的工具。毕竟,EDLIN 不是您通常想要用于文本编辑的工具,除非您有点自虐倾向。引用蒂姆·帕特森(编写它的人)的话:“当我听说 IBM 正在使用它而不是把它扔到窗外时,我惊呆了。”
注意:EDLIN 将老式的 EOF (1A) 标记添加到它编辑的文件中。如果您需要删除它们,您可能必须使用 DEBUG。
当将未知数量的参数传递给批处理文件时,例如,当将多个文件拖放到批处理文件上以启动它时,您可以按名称引用每个参数变量,例如
TYPE %1
TYPE %2
TYPE %3
TYPE %4
TYPE %5
...etc
但是当您要检查每个参数是否存在时,这会变得非常混乱:
if [%1] NEQ [] (
TYPE %1
)
if [%2] NEQ [] (
TYPE %2
)
if [%3] NEQ [] (
TYPE %3
)
if [%4] NEQ [] (
TYPE %4
)
if [%5] NEQ [] (
TYPE %5
)
...etc
此外,您只能使用这种方法接受有限数量的参数。
相反,请尝试使用 SHIFT 命令:
:loop
IF [%1] NEQ [] (
TYPE %1
) ELSE (
GOTO end
)
SHIFT
GOTO loop
:end
SHIFT 会将所有参数向下移动 1,因此 %2 变为 %1 并且 %3 变为 %2 等等。
FIND
作为grep的替代品。
我用 find 为自己破解了一个小“电话簿”。非常有用:
@echo off
:begin
set /p term=Enter query:
type phonebookfile.txt |find /i "%term%"
if %errorlevel% == 0 GOTO :choose
echo No entry found
set /p new_entry=Add new entry:
echo %new_entry% >> phonebookfile.txt
:choose
set /p action=(q)uit, (n)ew query or (e)dit? [q]
if "%action%"=="n" GOTO anfang
if "%action%"=="e" (
notepad phonebookfile.txt
goto :choose
)
非常快速有效。
基于行的执行
虽然在大多数情况下不是一个明显的好处,但它可以在尝试更新正在运行的东西时提供帮助。例如:
更新源.bat
copy UpdateSource.bat Current.bat
echo "Hi!"
当前.bat
copy UpdateSource.bat Current.bat
现在,执行 Current.bat 会产生这个输出。
HI!
但请注意,批处理执行按行号进行。如果基本行没有完全相同的行号,这样的更新最终可能会跳过或移回一行。
我将它们用作常用目录的快捷方式。一个名为“sandbox.bat”的示例文件,它位于我的 PATH 目录中
EXPLORER "C:\Documents and Settings\myusername\Desktop\sandbox"
调用脚本只需 WIN+R --> 沙箱
要获取用于日志文件等的当前日期/时间,我在批处理文件中使用它:
for /f "usebackq tokens=1,2,3,4,5,6,7 delims=/:. " %%a in (`echo %DATE% %TIME%`) do set NOW=%%d%%b%%c_%%e%%f%%g
set LOG=output_%NOW%.log
您可以在批处理文件运行时对其进行修改。例如,pause
如果您想在批处理文件退出之前查看结果,可以在文件运行时在文件末尾添加忘记。
请参阅在运行时更改批处理文件
我个人认为这更像是一个陷阱而不是一个功能。
要从文件的第一行设置环境变量,我使用以下命令:
rem a.txt contains one line: abc123
set /p DATA=<a.txt
echo data: %DATA%
这将输出:abc123
批处理脚本最常见的要求之一是记录生成的输出以供以后查看。是的,您可以将 stdout 和 stderr 重定向到一个文件,但是除非您跟踪日志文件,否则您将看不到发生了什么。
因此,请考虑使用像 logger 这样的 stdout/stderr 日志记录实用程序运行批处理脚本,该实用程序将使用时间戳记录输出,并且您仍然可以在脚本发生时看到脚本进度。
Yet another stdout/stderr logging utility [2010-08-05]
Copyright (C) 2010 LoRd_MuldeR <MuldeR2@GMX.de>
Released under the terms of the GNU General Public License (see License.txt)
Usage:
logger.exe [logger options] : program.exe [program arguments]
program.exe [program arguments] | logger.exe [logger options] : -
Options:
-log <file name> Name of the log file to create (default: "<program> <time>.log")
-append Append to the log file instead of replacing the existing file
-mode <mode> Write 'stdout' or 'stderr' or 'both' to log file (default: 'both')
-format <format> Format of log file, 'raw' or 'time' or 'full' (default: 'time')
-filter <filter> Don't write lines to log file that contain this string
-invert Invert filter, i.e. write only lines to log file that match filter
-ignorecase Apply filter in a case-insensitive way (default: case-sensitive)
-nojobctrl Don't add child process to job object (applies to Win2k and later)
-noescape Don't escape double quotes when forwarding command-line arguments
-silent Don't print additional information to the console
-priority <flag> Change process priority (idle/belownormal/normal/abovenormal/high)
-inputcp <cpid> Use the specified codepage for input processing (default: 'utf8')
-outputcp <cpid> Use the specified codepage for log file output (default: 'utf8')
提取随机文本行
@echo off
:: Get time (alas, it's only HH:MM xM
for /f %%a in ('time /t') do set zD1=%%a
:: Get last digit of MM
set zD2=%zD1:~4,1%
:: Seed the randomizer, if needed
if not defined zNUM1 set /a zNUM1=%zD2%
:: Get a kinda random number
set /a zNUM1=zNUM1 * 214013 + 2531011
set /a zNUM2=zNUM1 ^>^> 16 ^& 0x7fff
:: Pull off the first digit
:: (Last digit would be better, but it's late, and I'm tired)
set zIDX=%zNUM2:~0,1%
:: Map it down to 0-3
set /a zIDX=zIDX/3
:: Finally, we can set do some proper initialization
set /a zIIDX=0
set zLO=
set zLL=""
:: Step through each line in the file, looking for line zIDX
for /f "delims=@" %%a in (c:\lines.txt) do call :zoo %zIDX% %%a
:: If line zIDX wasn't found, we'll settle for zee LastLine
if "%zLO%"=="" set zLO=%zLL%
goto awdun
:: See if the current line is line zIDX
:zoo
:: Save string of all parms
set zALL=%*
:: Strip off the first parm (sure hope lines aren't longer than 254 chars)
set zWORDS=%zALL:~2,255%
:: Make this line zee LastLine
set zLL=%zWORDS%
:: If this is the line we're looking for, make it zee LineOut
if {%1}=={%zIIDX%} set zLO=%zWORDS%
:: Keep track of line numbers
set /a zIIDX=%zIIDX% + 1
goto :eof
:awdun
echo ==%zLO%==
:: Be socially responsible
set zALL=
set zD1=
set zD2=
set zIDX=
set zIIDX=
set zLL=
set zLO=
:: But don't mess with seed
::set zNUM1=
set zNUM2=
set zWORDS=