Windows批处理文件的隐藏功能


232

Windows批处理文件中鲜为人知但重要且有用的功能有哪些?

指导原则:

  • 每个答案一项功能
  • 提供功能的简短说明示例,而不仅仅是文档的链接
  • 将答案限制为本机功能,即不需要其他软件,例如Windows Resource Kit

澄清:我们这里指的是cmd.exe处理的脚本,这是WinNT变体的默认设置。

(另请参阅:Windows批处理文件:.bat与.cmd?

Answers:


185

行继续:

call C:\WINDOWS\system32\ntbackup.exe ^
    backup ^
    /V:yes ^
    /R:no ^
    /RS:no ^
    /HC:off ^
    /M normal ^
    /L:s ^
    @daily.bks ^
    /F daily.bkf

2
我上周一直在寻找!(不记得角色)
chilltemp

21
^实际上是一个引号字符。使用它,您可以引用<和>,以便它们不会重定向输出。行尾的^也允许行继续。
Cheeso

您能解释一下这个小脚本吗?
guerda

2
@furtelwart:这就像您将所有内容写到一行中一样:call C:\WINDOWS\system32\ntbackup.exe backup /V:yes /R:no /RS:no /HC:off /M normal /L:s @daily.bks /F daily.bkf。要了解该行的所有参数,只需运行C:\WINDOWS\system32\ntbackup.exe /?
Kurt Pfeifle,2010年

关于此主题的深入讨论,长命令分成多行
jeb 2011年

150
PUSHD path

带您到path指定的目录。

POPD

带您回到“推送”的目录。


5
这也可以作为完整堆栈使用,因此您可以将许多目录压入堆栈,然后继续弹出以返回原来的位置。
Kibbee

认真吗 我怎么从未听说过此功能?
乔什·辛曼

4
运行“ cmd.exe”,然后键入“ help”,然后键入“ help pushd”或“ pushd /?”。
paxdiablo

86
如果您将其推送到UNC路径,它将自动为您映射驱动器,而popd会取消映射它。
Ferruccio

2
+1,尤其是对于UNC功能,您应该将其添加到答案中。
亚当·米兹

109

不确定这在批处理文件中将有多有用,但是在命令提示符下使用它是非常方便的命令:

C:\some_directory> start .

这将在“ some_directory”文件夹中打开Windows资源管理器。

我发现这节省了很多时间。


1
好吧,我也使用它。我在PATH目录之一中有一个“ open.cmd”文件,该文件中唯一的东西是“ @start”。;)
Paulius

5
'explorer'也和'start'C:\ some_directory> explorer相同。

1
我倾向于将其键入为[start“”。](为清楚起见,用括号括起来),因为开始有时对第一个参数是标题有些挑剔。
系统暂停

1
如果您碰巧是在Mac上,请open .执行相同的操作。
格兰特·保罗

1
start除了打开当前文件夹外,还可以做更多的事情。您可以将其传递给任何文件,它将使用配置的查看器将其打开。给它一个URL,然后您的默认浏览器打开,等等……
idbrii 2011年

87

我一直发现很难阅读每一行上由关键字标记的注释:

REM blah blah blah

更容易阅读:

:: blah blah blah

8
我听说::比REM更有效,因为REM尝试对它之后发生的事情进行环境变量扩展,但是::却没有。
Scott Langham

47
实际上,::只是一个带有有趣名称的标签;因此,如果在块中(用括号括起来)使用::,将不会起作用,因为那里也不允许使用标签。REM当然在那里工作。
mihi

请注意,尽管这rem是一个文档化的关键字,而::仅仅是实现细节。虽然不太可能::会停止工作,但通常建议不要依赖未记录的行为。
乔伊

您甚至可以使用goto :跳转到标签。 :-)并且goto -)也将起作用。
Sven Marnach 2011年

79

可变子串:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456

3
丑陋,但非常有用!
guerda

1
@furtelwart听起来像是批判的座右铭
rzrgenesys187

这非常适合格式化日期(但是我发现的问题是vista / 7和xp输出DATE的方式不同)
Daniel

注意,不幸的是,它不能与FOR循环(for %a in ...)的局部变量结合使用,因为它们不需要关闭变量百分号,也不需要环境变量。您必须首先将它们分配给环境变量(使用延迟扩展!),然后提取一个子字符串。
罗尔考2011年

如果您想对日期做一些事情(例如备份文件名),这是不可避免的丑陋。见证了Windows命令行的普遍丑陋之后,我明白了为什么Windows大多是指向&单击的:)尽管他们说新的PowerShell更好。
HalilÖzgür'2

72

FOR命令!尽管我讨厌编写批处理文件,但我对此表示感谢。

FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k

会解析myfile.txt中的每一行,而忽略以分号开头的行,将第二行和第三行令牌从每一行传递到for正文,并以逗号和/或空格分隔。请注意,for主体语句引用%i获取第二个令牌,%j获取第三个令牌,%k获取第三个之后的所有其余令牌。

您还可以使用它来遍历目录,目录内容等。


4
我发现批处理文件的FOR循环有限且编写起来很糟糕,但是有时它们很有用。
08年

2
对不起,请问,这到底是怎么利用的呢?我认为,如果您不知道FOR循环,就不知道批处理脚本。
编码风格

11
未被充分利用的是酷刑。(有些人会辩称必要的邪恶。)
harpo

我不得不使用它几次,应该解雇组成这种语法的人。从大炮。进入太阳。太糟糕了。
VitalyB

1
@CodingWithStyle:每当我需要在批处理文件中编写一个for循环时,该脚本就会变成bash启动器,并改用bash(或python)重写该脚本
:)

60

而不是用REM或::行填充脚本,我在每个脚本的顶部执行以下操作:

@echo OFF
goto :START

Description of the script.

Usage:
   myscript -parm1|parm2 > result.txt

:START

请注意如何在不转义的情况下使用管道字符和重定向字符。


3
如果您在%1上检查“ /”,会更酷。然后您可以将该部分作为帮助文本回显。
demoncodemonkey

6
嗯,有文化的批处理编程吗?
Muhammad Alkarouri

54

脚本所在的路径(带有驱动器):〜dp0

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%

我通常为此使用%CD%。也许不是所有的DOS Shell版本都可用?
Saul Dolgin

11
%CD%是当前目录,而%〜dp0是运行脚本所在的目录。
RealHowTo

另外,我认为%CD%可能早于... XP。我知道Windows的某些旧版本没有它。
Thomas Owens

1
如果蝙蝠在另一个驱动器中,则应改用cd / d%BAT_HOME%。如果我没记错的话,这不适用于较旧的DOS。
ketorin 2010年

如果在网络路径上运行批处理,则cd或推送的%BATH_HOME%将无法工作。
Benoit

49

已经提到了%〜dp0,但实际上还有更多内容:〜后面的字符定义了要提取的信息。
没有字母会导致返回补丁文件名称
d-返回驱动器字母
p-返回路径
s-返回短路径
x-返回文件扩展名
因此,如果从c:\ Temp执行以下脚本test.bat \长目录名\文件夹,

@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\

并且,如果像
测试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

43

通过使用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。


6
您应该使用goto:eof而不是exit / b来执行相同的操作,但这是更标准的方法。
Philibert Perusse

2
有这个标准吗?O_o
Paulius

3
我的错。我以为您的意思是显式定义:eof标签并对其进行跳转。我没有意识到在每个批处理文件的末尾都有一个隐含的:eof标签。
Ferruccio

3
但是,如果希望子例程设置错误级别,则需要使用exit / b。例如:exit / b 3
Chris Noe

6
我发现最好使用“ exit / B”而不是“ goto:eof”从子例程返回,“ goto:eof”有一个问题,当您要吞下它时可能会返回错误代码。例如,如果您使用“ if somefile echo it is here,如果存在”,这将设置错误级别,如果someFile不存在,但这不是错误的,并且不是您要返回的错误代码(这就是“ goto:eof“即可)。
斯科特·朗厄姆

42

等待N秒(不属于cmd.exe的一部分,但由于Windows附带,它不是额外的软件)的狡猾trick俩,请参阅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

2
更好的做法是将其放入sleep.bat之类的文件中,以免您一遍又一遍地重写它。
erjiang

1
...并将sleep.bat放在PATH环境变量中的某个目录中
Scoregraphic

我反对把它放到外面,使它们在Windows系统上的可移植性降低。
索林

37

转义“管道”:

echo ^| ^< ^> ^& ^\ ^^

3
我敢打赌,DOS转义字符并不为人所知。好一个
约书亚

12
嗯,这也解释了为什么它也是行继续操作符的原因-它像bash中的\一样转义了换行符
leander

@leander:是的,但是它只能逃脱LF(而不是CR),因为所有CR都在此之前被删除了
jeb 2010年

因此,就是为什么在Windows上使用git与前一个commit(HEAD^)进行比较时会出现问题的原因。
Daniel Trebbien

31

能够运行命令并处理输出(例如bash中'$()'的反引号)。

for /f %i in ('dir /on /b *.jpg') do echo --^> %i

如果文件名中有空格,请使用以下命令:

for /f "tokens=*" %i in ('dir /on /b *.jpg') do echo --^> %i

2
不适用于名称中带有空格的文件名...可以正常工作:对于/ f“ tokens = *”%i in('dir / on / b * .jpg'),执行echo-^>%i
doekman

接得好。我个人认为,从地狱第九圈的深度来看,文件名中的空格是邪恶的丑陋事物。但我想我们应该照顾他们。
paxdiablo

这是我所见过的最疯狂的语法。如果您制作了这个backtick.bat并传入了字符串,是否可以正常工作?
idbrii 2011年

30

创建一个空文件:

> copy nul filename.ext

6
@devio:回声。放一个空行。因此文件不会为空!
Paulius

4
我用type nul > filename.ext那个。
Benoit

很好,我想知道很长一段时间是否有触摸效果。
jdelator

我一直在使用ren > blah.txt
Synetech 2011年

28

要隐藏命令的所有输出,请重定向到> nul 2>&1。

例如,即使您重定向到> nul,某些命令行程序也会显示输出。但是,如果您像下面的行一样重定向输出,则所有输出将被抑制。

PSKILL NOTEPAD >nul 2>&1

编辑:请参阅忽略命令的输出以获取有关其工作原理的说明。


1
你知道这是怎么回事吗?2>&1位是什么意思?
Scott Langham

12
> nul将STDOUT重定向到nul。2>&1将STDERR重定向到STDOUT指向的任何位置。
Aphoria

具体来说,我认为2>&1是“文件句柄克隆”,将STDERR设置为STDOUT的克隆。将其放在> NUL之后很重要,因为您要在重定向STDOUT 之后而不是之前克隆它。(如果我在这里错了,请指正。)
利安德

1
如果您想知道PSKILL的来源,请访问sysinternals.com。如果您使用的是专业版,则应该具有一个基本相同的本机TSKILL命令。
编码风格

1
如果您没有pskill或tskill,那么我使用的大多数Windows系统都附带了taskkill
idbrii 2011年

25
PAUSE

停止执行并显示以下提示:

按任意键继续 。。。

如果要通过在Windows资源管理器中双击批处理来运行批处理,并且希望实际看到输出而不只是命令窗口的闪烁,该命令很有用。


在将其标记到我编写的每个脚本的末尾时,我几乎不会称其为“未充分利用”。再说一次,当您想让您的IDE运行脚本并捕获输出时,效果就不太好了,因为IDE通常无法为您按Enter键……
Nicholas Flynt

15
“暂停”的一个简洁功能是,如果没有终端可以接收“任何密钥”(例如,如果您的批处理文件是从系统服务运行的),它会检测到这一点并继续运行...
leander

4
+1给查理·萨默维尔(Charlie Somerville),众所周知,每个游戏程序员的“ go.bat”早在90年代就使用了它。
LiraNuna

6
您可以使用Start / Run /然后输入'cmd / k'和批处理文件名,而不是污染所有的批处理文件(并使它们烦人于CLI极客)。或将HKCR \ batfile \ shell \ open \ command默认字符串更改为'cmd / k“%1”%*'。或者制作另一个仅运行'@cmd / k $ *'的批处理文件,将其放在桌面上,然后将其他批处理文件放到该文件上。有很多替代PAUSE的方法。请考虑一下。
系统

1
@gnud:您仍然可以通过管道传递到脚本:echo.|batch-with-pause.bat与按“ any-key”具有相同的效果...
Kurt Pfeifle 2010年

25

相当于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上则不行。


18

设置环境变量时进行搜索和替换:

> @set fname=%date:/=%

...从日期中删除带有时间戳记的文件名中的“ /”。

还有子串...

> @set dayofweek=%fname:~0,3%

17

整数运算:

> SET /A result=10/3 + 1
4

SET可以计算多长时间了?Windows XP?
chakrit

1
如果您问值可以有多大,我相信这是32位的。因此,+ /-20亿。
克里斯·诺

1
我认为问题是,SET能够计算多长时间了?从Windows XP开始?
迈克尔·迈尔斯

3
自从NT 3.1左右以来,我就可以计算CMD.EXE的SET。所有人花了很长时间才注意到CMD.EXE与COMMAND.COM并不完全相同...
RBerteig

16

命令分隔符:

cls & dir
copy a b && echo Success
copy a b || echo Failure

在第二行,&&之后的命令仅在第一个命令成功的情况下运行。

在第三行,||之后的命令 仅在第一个命令失败时运行。



15

您可以将if语句链接起来,以获得类似于短路布尔值“ and”的效果。

if foo if bar baz

1
这实际上只是嵌套ifs的捷径:(if foo ( if bar ( baz ) )想象一下括号后的换行符。)
idbrii 2011年

14

快速将Unicode文本文件(16位/字符)转换为ASCII DOS文件(8位/字符)。

C:\> type unicodeencoded.txt > dosencoded.txt

另外,如果可能的话,可以正确映射字符。


1
那是一个ANSI DOS文件-ASCII是7位/字符。
MarkJ

大声笑,这是一种反模式,这种转换很可能失败。支持Unicode的唯一8位编码是UTF-8,但是由于有了M $,您无法在Windows上设置UTF-8代码页。
索林

14

if块结构:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)

3
只要您知道变量将一次性全部扩展(没有延迟扩展)-即您不能在其中明智地使用%ERRORLEVEL%。
Duncan Smart 2009年

您也不能在那里使用标签(包括那些::样式注释),因为它会过早地结束if语句。
编码样式

2
@邓肯:%ERRORLEVEL%无论如何,你不应该使用伪变量;那if errorlevel <foo>是为了什么。而确实在这样的块实际上工作。
乔伊

12

延迟扩展变量(以适当的方式插入子字符串):

    @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

12

它并没有提供太多功能,但是您可以将title命令用于多种用途,例如在任务栏中的长脚本上提供状态,或者只是增强用户反馈。

@title Searching for ...
:: processing search
@title preparing search results
:: data processing

2
有趣。尽管此后您显然失去了常规功能,该功能将显示当前正在运行的命令。有什么办法可以重置吗?
克里斯·诺

2
technet.microsoft.com/en-us/library/bb491017.aspx说,它可以复位与自己的“头衔”,但这似乎没有工作在Windows 7上......不
ℳ。

11

没有方便的编辑器,需要创建批处理文件吗?

copy con test.bat

只需键入命令,然后按Enter即可换行。按Ctrl-Z和Enter键以关闭文件。


4
嘿,那带我回来。
编码风格

11

字符串减法示例datetime获取名为“ 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到的十六进制值F,其中X-背景,Y-文本,当X = Y时颜色不变。

颜色Z

将文字颜色更改为“ Z”并设置黑色背景,“颜色0”将不起作用

用于颜色名称的呼叫

颜色?


编辑; _被解释为斜体。不错的代码。

@Duncan Smart:不是,也可以在英国英语中使用(尽管从技术上讲应该是“ colour”,grrr)
demoncodemonkey

10

通过空格和转义符完全控制输出:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>

1
这是如何运作的?点分隔文本输出的开头?
克里斯·诺

3
“ echo。x”将输出“ <space> x”,“ echo x”将仅输出“ x”。这允许前导空格。另外,“ ^”转义字符将阻止cmd认为所有那些“ <”和“>”字符都是I / O重定向。
paxdiablo

1
回声(比较好,因为回声创建了一个名为“回声”如果这个文件存在回声失败,如果不是则执行内部回声文件的文件搜索,但它是慢于回声(。
杰布

9

TheSoftwareJedi已经提到了for命令,但是由于它非常强大,我将再次提及它。

以下以YYYYMMDD格式输出当前日期,我在生成用于备份的目录时使用它。

for /f "tokens=2-4 delims=/- " %a in ('DATE/T') do echo %c%b%a

2
当然,DATE / T在欧洲返回29/10/2008,在美国返回10/29/2008 ...因此可能需要一些本地化!;-)

那就对了!但是您可以滥用date命令来查找使用哪种日期格式。
08年

4
imo过度使用了FOR。我想我只使用%DATE:〜10,4 %% DATE:〜4,2 %% DATE:〜7.2%,而不是运行date命令然后对其进行解析。
编码风格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.