Windows批处理文件的隐藏功能

Chr*_*Noe 232 windows hidden-features batch-file

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

指南:

  • 每个答案一个功能
  • 给出功能的简短描述示例,而不仅仅是文档的链接
  • 限制原生功能的答案,即不需要其他软件,如Windows资源工具包

澄清:我们在这里指的是由cmd.exe处理的脚本,这是WinNT变体的默认值.

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

Chr*_*Noe 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
Run Code Online (Sandbox Code Playgroud)

  • ^实际上是一个引用字符.使用它,您可以引用<和>,以便它们不会重定向输出.行末尾的^也允许行继续. (21认同)
  • 我上周正在寻找这个!(不记得这个角色) (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 /?`. (2认同)

rav*_*ven 150

PUSHD path
Run Code Online (Sandbox Code Playgroud)

转到path指定的目录.

POPD
Run Code Online (Sandbox Code Playgroud)

带你回到你"推"的目录.

  • 如果您推送到UNC路径,它将自动为您映射驱动器,popd将取消映射它. (86认同)
  • 这也可以作为一个完整的堆栈,因此你可以将许多目录推入堆栈,然后继续弹出以回到原来的位置. (5认同)
  • 运行'cmd.exe'然后输入'help',然后输入'help pushd'或'pushd /?'. (4认同)
  • 特别是对于UNC功能+1,您应该将其添加到您的答案中. (2认同)

Leo*_*Hat 109

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

C:\some_directory> start .
Run Code Online (Sandbox Code Playgroud)

这将在"some_directory"文件夹中打开Windows资源管理器.

我发现这是一个很好的节省时间.

  • 'explorer'也和'start'C:\ some_directory> explorer一样. (5认同)

Chr*_*Noe 87

我一直觉得很难阅读每行上用关键字标记的评论:

REM blah blah blah
Run Code Online (Sandbox Code Playgroud)

更易于阅读:

:: blah blah blah
Run Code Online (Sandbox Code Playgroud)

  • 事实上,::只是一个有趣名字的标签; 因此,如果你在一个块内(在括号中)使用它将不起作用,因为那里也不允许标签.REM当然在那里工作. (47认同)
  • 我听说::比REM更有效,因为REM试图对它之后发生的事情进行环境变量扩展,但是::没有. (8认同)

Chr*_*Noe 79

变量子串:

> set str=0123456789
> echo %str:~0,5%
01234
> echo %str:~-5,5%
56789
> echo %str:~3,-3%
3456
Run Code Online (Sandbox Code Playgroud)

  • 丑陋,但很有用! (3认同)

The*_*edi 72

FOR命令!虽然我讨厌编写批处理文件,但我很感激.

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

将解析myfile.txt中的每一行,忽略以分号开头的行,将第2和第3个标记从每行传递给for body,并用逗号和/或空格分隔标记.注意for body语句引用%i获取第二个标记,%j获取第三个标记,%k获取第3个标记之后的所有剩余标记.

您也可以使用它来迭代目录,目录内容等...

  • 未充分利用与否,这是折磨.(有些人认为必要的邪恶.) (11认同)
  • 我发现批处理文件'FOR循环有限且写得很糟糕,但它们有时很有用. (4认同)
  • 请原谅我的困惑,但这究竟是如何未被充分利用的呢?我想如果你不知道FOR循环,你不知道批处理脚本. (2认同)

Pat*_*uff 60

我没有在REM或:: lines中乱丢脚本,而是在每个脚本的顶部执行以下操作:

@echo OFF
goto :START

Description of the script.

Usage:
   myscript -parm1|parm2 > result.txt

:START
Run Code Online (Sandbox Code Playgroud)

请注意如何使用管道和重定向字符而不转义它们.

  • 嗯,有文化的批量编程?! (6认同)
  • 如果你检查%1为"/?"会更酷吗?然后你可以将该部分作为帮助文本回显. (3认同)

Rea*_*wTo 54

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

set BAT_HOME=%~dp0
echo %BAT_HOME%
cd %BAT_HOME%
Run Code Online (Sandbox Code Playgroud)

  • %CD%是当前目录,而%~dp0是运行脚本所在的目录. (11认同)

小智 49

已经提到了%~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
Run Code Online (Sandbox Code Playgroud)

你得到以下输出

test
c:
\Temp\long dir name\
c:\Temp\long dir name\
.bat
c:\Temp\LONGDI~1\test.bat
\Temp\LONGDI~1\
Run Code Online (Sandbox Code Playgroud)

如果参数像
测试c:\ temp\mysrc\test.cpp
一样传递到脚本中,则可以使用%1变量完成相同的操作.

但是%0扩展的结果取决于位置!
在批处理的"顶层",它扩展为当前批处理文件名.
在函数(调用)中,它扩展为函数名称.

@echo off
echo %0
call :test
goto :eof

:test
echo %0
echo %~0
echo %~n0
Run Code Online (Sandbox Code Playgroud)

输出是(批处理文件以myBatch.bat启动)

myBatch.bat
:test
:test
myBatch
Run Code Online (Sandbox Code Playgroud)


Fer*_*cio 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
Run Code Online (Sandbox Code Playgroud)

这将打印

11
xxxxx
Run Code Online (Sandbox Code Playgroud)

即使:sub修改x.

  • 你应该使用goto:eof而不是exit/b,做同样的事情,但是更标准的方法. (6认同)
  • 我发现最好使用"exit/B"而不是"goto:eof"从子程序返回,"goto:eof"有一个问题,当你想要吞下它时你可能会返回一个错误代码.例如,如果您使用"如果存在someFile回显它在这里",这将设置errorlevel如果someFile不存在,但这没有错,并且不是您想要返回的错误代码(这是什么"转到:eof"会这样做". (6认同)
  • 我的错.我认为你的意思是明确定义一个:eof标签并对其进行转换.我没有意识到每个批处理文件末尾都有一个隐含的:eof标签. (3认同)
  • 但是,如果您希望子例程设置errorlevel,则需要使用exit/b.例如:exit/b 3 (3认同)
  • 这有一个标准吗?O_O (2认同)

pax*_*blo 42

偷偷摸摸的技巧等待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
Run Code Online (Sandbox Code Playgroud)

  • 更好的是把它放在像sleep.bat这样的文件中,以免你一遍又一遍地重写它. (2认同)

Chr*_*Noe 37

逃离"管道":

echo ^| ^< ^> ^& ^\ ^^
Run Code Online (Sandbox Code Playgroud)

  • 啊,这就解释了为什么它也是行继续运算符 - 它逃脱了换行符,就像在bash中一样...... (12认同)
  • 我敢打赌,DOS转义字符并不为人所知.好的. (3认同)

pax*_*blo 31

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

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

如果文件名中有空格,请使用:

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

  • 不适用于名称中包含空格的文件名...这有效:for/f"tokens =*"%i in('dir/on/b*.jpg')做回声 - ^>%i (2认同)

nzp*_*mad 30

创建一个空文件:

> copy nul filename.ext
Run Code Online (Sandbox Code Playgroud)

  • @devio:回声.放空行.所以文件不会是空的! (6认同)
  • 我使用`type nul> filename.ext`. (4认同)

aph*_*ria 28

隐藏命令重定向到> nul 2>&1的所有输出.

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

PSKILL NOTEPAD >nul 2>&1
Run Code Online (Sandbox Code Playgroud)

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

  • > nul将STDOUT重定向到nul.2>&1将STDERR重定向到STDOUT指向的任何位置. (12认同)

rav*_*ven 25

PAUSE
Run Code Online (Sandbox Code Playgroud)

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

Press any key to continue . . .

有用的,如果你想通过双击它在Windows资源管理器运行批处理,并希望见到实际的输出,而不是只是一个命令行窗口中闪光.

  • "暂停"的一个简洁特征是,如果没有终端接收"任何密钥"(例如,如果您的批处理文件是从系统服务运行的),它会检测到这一点并继续... (15认同)
  • 您可以使用"开始/运行"/然后键入"cmd/k"和批处理文件名,而不是污染所有批处理文件(并使其难以用于CLI极客).或者将HKCR\batfile\shell\open \命令默认字符串更改为'cmd/k"%1"%*'.或者制作另一个只运行'@cmd/k $*'的批处理文件,将其放在桌面上并删除其他批处理文件.PAUSE有很多替代方案.请考虑一下. (6认同)
  • 给Charlie Somerville +1,这是众所周知的每个游戏程序员的'go.bat'在90年代早期使用它. (4认同)

pax*_*blo 25

相当于bash(和其他shell)

echo -n Hello # or
echo Hello\\c
Run Code Online (Sandbox Code Playgroud)

输出" Hello"没有尾随换行符.一个cmd hack来做到这一点:

<nul set /p any-variable-name=Hello
Run Code Online (Sandbox Code Playgroud)

set /p是一种提示用户输入的方法.它发出给定的字符串然后等待(在同一行,即没有CRLF),以便用户键入响应.

<nul只需管道对set /p命令的空响应,因此最终结果是发出的提示字符串.(由于空的响应,使用的变量保持不变.)

问题是:输出一个前导等号是不可能的,并且在Vista上领先的空白字符被删除,但不是在XP上.


Sql*_*CID 18

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

> @set fname=%date:/=%
Run Code Online (Sandbox Code Playgroud)

...从用于时间戳文件名的日期中删除"/".

和子串...

> @set dayofweek=%fname:~0,3%
Run Code Online (Sandbox Code Playgroud)


Chr*_*Noe 17

整数算术:

> SET /A result=10/3 + 1
4
Run Code Online (Sandbox Code Playgroud)

  • 我的事情CMD.EXE的SET已经能够计算自NT 3.1左右.人们花了很长时间才注意到CMD.EXE与COMMAND.COM不完全相同...... (3认同)

doe*_*man 16

命令分隔符:

cls & dir
copy a b && echo Success
copy a b || echo Failure
Run Code Online (Sandbox Code Playgroud)

在第二行,&&仅在第一个命令成功时运行.

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


小智 15

您可以链接if语句以获得类似短路布尔"和"的效果.

if foo if bar baz
Run Code Online (Sandbox Code Playgroud)


Rea*_*wTo 14

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

C:\> type unicodeencoded.txt > dosencoded.txt
Run Code Online (Sandbox Code Playgroud)

作为奖励,如果可能,正确映射字符.


Fer*_*cio 14

如果块结构:

if "%VS90COMNTOOLS%"=="" (
  echo: Visual Studio 2008 is not installed
  exit /b
)
Run Code Online (Sandbox Code Playgroud)

  • 只要你知道变量将一次性扩展(没有延迟扩展) - 即你不能合理地使用%ERRORLEVEL%. (3认同)
  • @Duncan:你不应该使用伪变量`%ERRORLEVEL%`; 这就是`if errorlevel <foo>`的用途.并且**实际上在这些块中起作用. (2认同)

pax*_*blo 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
Run Code Online (Sandbox Code Playgroud)


小智 12

不提供太多功能,但您可以将title命令用于几个用途,例如在任务栏中的长脚本上提供状态,或者只是为了增强用户反馈.

@title Searching for ...
:: processing search
@title preparing search results
:: data processing
Run Code Online (Sandbox Code Playgroud)

  • 有趣.虽然此后你显然失去了常规功能,即显示当前运行的命令.有没有办法重置? (2认同)
  • http://technet.microsoft.com/en-us/library/bb491017.aspx表示它可以自行重置"标题",但这似乎不适用于Windows 7 ... (2认同)

Mor*_*aos 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是从十六进制值0F,其中X -背景,Y -文本中,当X = Y颜色不会改变.

颜色Z.

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

用于调用颜色的名称

颜色?


小智 11

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

copy con test.bat
Run Code Online (Sandbox Code Playgroud)

只需键入命令,按Enter键即可获得新行.按Ctrl-Z和Enter关闭文件.

  • 嘿,这让我回来了. (4认同)

pax*_*blo 10

使用间距和转义字符对输出进行完全控制:

echo.    ^<resourceDir^>/%basedir%/resources^</resourceDir^>
Run Code Online (Sandbox Code Playgroud)

  • "echo.x"将输出"<space> x","echo x"将仅输出"x".这允许前导空间.此外,"^"转义字符将阻止cmd认为所有那些"<"和">"字符都是I/O重定向. (3认同)

小智 9

TheSoftwareJedi已经提到了for命令,但是我会再次提到它,因为它非常强大.

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

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

  • 它过度使用FOR,imo.我想我只会使用%DATE:~10,4 %% DATE:~4,2 %% DATE:~7,2%,而不是运行日期命令然后解析它. (4认同)
  • 当然DATE/T在欧洲和2008年10月29日在美国的29/10/2008返回...所以可能需要一些本地化!;-) (2认同)

Lar*_*gan 8

您可以使用call来稍后评估名称,从而产生一些有用的属性.

call set SomeEnvVariable_%extension%=%%%somevalue%%%
Run Code Online (Sandbox Code Playgroud)

使用call来设置名称取决于其他变量的变量.如果与某些变量命名规则一起使用,则可以使用仔细的命名规则来模拟数组(如数组或字典).在某个值周围的三重%是如此,它将在调用之后和调用set之前评估为由单个%包围的一个变量名.这意味着连续两个%转义为单个%字符,然后它会再次展开它,因此somevalue实际上是一个名称指针.

call set TempVar=%%SomeEnvVariable_%extension%%%
Run Code Online (Sandbox Code Playgroud)

将它与temp变量一起使用以检索该值,然后可以在逻辑中使用该值.当与延迟变量扩展一起使用时,这最有用.

要正确使用此方法,需要启用延迟变量扩展.因为它默认是关闭的,所以最好在脚本中启用它,方法是将其作为第一条指令之一:

setlocal EnableDelayedExpansion
Run Code Online (Sandbox Code Playgroud)


pax*_*blo 7

在路径上搜索可执行文件(或者在必要时搜索其他类似路径的字符串):

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:\>
Run Code Online (Sandbox Code Playgroud)


mat*_*kie 7

关于使用::而不是REM评论:小心!::是一个CALL标签的特例,其作用类似于注释.当在括号内使用时,例如在FOR或IF循环中,该函数将过早退出.调试非常令人沮丧!

有关完整说明,请访问http://www.ss64.com/nt/rem.html.

(在第一次提到上述内容时添加新答案而不是评论,因为我不值得赞扬:0)


Cod*_*yle 6

这些天很多人使用GOTO:EOF来终止他们的批处理文件,但你也可以使用EXIT/B来实现这个目的.

使用EXIT/B的优点是你可以在EXIT/B之后添加一个错误级别,它将以错误级别退出.


Cod*_*yle 6

仍然会为ENDLOCAL使用的行解析局部变量.这允许像下面这样的技巧:

ENDLOCAL & SET MYGLOBAL=%SOMELOCAL% & SET MYOTHERGLOBAL=%SOMEOTHERLOCAL%
Run Code Online (Sandbox Code Playgroud)

这是将结果传输到调用上下文的有用方法.具体来说,一旦ENDLOCAL完成,%SOMELOCAL%就会超出范围,但到那时%SOMELOCAL%已经展开,因此MYGLOBAL在调用上下文中使用局部变量进行分配.

出于同样的原因,如果您决定这样做:

ENDLOCAL & SET MYLOCAL=%MYLOCAL%
Run Code Online (Sandbox Code Playgroud)

您将发现新的MYLOCAL变量实际上是作为常规环境变量而不是您可能想要的本地化变量.


pax*_*blo 5

子程序(输出42):

    @echo off
    call :answer 42
    goto :eof
:do_something
    echo %1
    goto :eof
Run Code Online (Sandbox Code Playgroud)

和子程序返回一个值(输出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
Run Code Online (Sandbox Code Playgroud)


小智 5

cmd.exe中的快速编辑模式是我的最爱.这稍微偏离了主题,但是当与命令shell交互时,它可以成为救生员.不,我不是双曲线 - 在你死之前你只会看到一些次数的插入符号 ; 你看得越多,你死得越快.

  1. 打开注册表(小心,不是我的错,蓝屏等)
  2. 转到HKCU/Console
  3. 将QuickEdit设置为1

(你也可以在UI中设置这个,这可能是更好的方法.请参阅注释以获取说明.还有一个很好的单行脚本也可以这样做.)

现在,要复制,只需单击鼠标左键并拖动即可选择并右键单击进行复制.要粘贴,只需右键单击即可.

没有更多的时间^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V ^ V !!!

废话,我想我刚刚杀了一个人.抱歉!

  • 您无需直接编辑注册表即可设置此项.单击窗口左上角的命令提示符图标.选择属性.在"选项"选项卡上,选中"快速编辑模式"框. (5认同)

And*_*ris 5

调用集 - 将环境变量扩展到几个级别.

http://ss64.com/nt/call.html#advanced找到这个从回答另一个SO问题批量文件变量在for循环中初始化

set VarName=Param
set Param=This

call set Answer=%%%Varname%%%
Echo %Answer%
Run Code Online (Sandbox Code Playgroud)

set VarName=Param
set Param=This
call set Answer=%Param%
Echo This
This
Run Code Online (Sandbox Code Playgroud)