Windows Batch 1-4

Guide to Windows Batch Scripting

http://steve-jansen.github.io/guides/windows-batch-scripting/index.html

Overview

batch可以帮助配置 DevOps , 提高每天的工作效率.

Part 1 – Getting Started

Launching the Command Prompt

keyboard shortcut Windows Logo Key + R

输入cmd.exe

Editing Batch Files

Windows Logo Key + R 输入 notepadnotepad++

batch文件是 ASCII text, 差不多所有的编辑器都可以用来编辑它;

Viewing Batch Files

可以直接在编辑器中查看batch文件;

在 DOS cmmand中可以使用下列命令查看文件:

- TYPE myscript.cmd

- MORE myscript.cmd

- EDIT myscript.cmd

Batch File Names and File Extensions

建议的后缀名: .cmd

90年代的 Windows使用 .bat

区别:

avoid some rare side effects with .bat files

The differences between .CMD and .BAT as far as CMD.EXE is concerned are: With extensions enabled, PATH/APPEND/PROMPT/SET/ASSOC in .CMD files will set

ERRORLEVEL regardless of error. .BAT sets ERRORLEVEL only on errors.

使用 .cmd后缀名, 你可以使用任何文件名; 建议不要在文件名中加入空格, 在 shell脚本中空格只会带来麻烦;

利用Pascal cast可以帮助避免空格;

e.g. 使用 HelloWorld.cmd代替 Hello World.cmd; 可以使用标点如 . or - or _ (e.g. Hello.World.cmd, Hello-World.cmd, Hello_World.cmd)

另外要注意的是, 避免和 built-in的 command, 系统文件或者流行的程序重名.

e.g. 避免使用 ping.cmd为已经有了一个广泛使用的系统文件 ping.exe ; 如果你无意间运行 ping, 有可能是调用了 ping.cmd而不是真正想要的 ping.exe, 那么情况会变得很令人困惑.

建议使用 RemoteHeartbeat.cmd或在脚本名字中添加一些细节, 这样还能避免和其他的可执行文件发生名字冲突.

当然, 也存在很特殊的情况: 就是你想把ping的默认行为修改掉, 那么可以无视这里的名字规范.

Saving Batch Files in Windows

Notepad默认会尝试将所有文件当做 plain jane text[普通]文件格式保存;

要让 Notepad将文件保存为 .cmd格式, 需要使用 “Save as type”下拉菜单选为 “All Files(.)”;

注意, Encoding选项, 英文一般为 ASCII.

e.g. 文件名设为 %USERPROFILE%\HelloWorld.cmd

%USERPROFILE%关键字是 Windows环境变量, 代表 user profile文件夹的目录地址; 在较新的 Windows系统中, user profile文件夹一般是: C:\Users\<your username>;

这个shortcut可以帮你省点时间, 因为一个新的 command prompt通常是默认是在你的 user profile文件夹的 “working directory”目录下;

有了这个shortcut, 就可以不用预先修改当前目录或者指定脚本路径了.

Running your Batch File

运行batch文件的简单方式是双击文件; 不过, 在command prompt中才有机会看到更多的output和error.

当脚本退出的时候, command prompt的窗口会立即消失. ()参见 Part 10 – Advanced Tricks)

运行一个新脚本时, 你可能向要在打开的command窗口中运行batch文件; 对于初学者, 可以直接把脚本拖到command prompt窗口中; command prompt在command line显示出脚本的全路径, 将包含空格的路径用引号括起.

Tips:

- 可以按上下箭头键. 在command line历史中查找用过的命令.

- %COMPSPEC% /C /D "C:\Users\User\SomeScriptPath.cmd" Arg1 Arg2 Arg3

这个命令让脚本在一个新的command prompt 子进程中运行. /C选项表示脚本结束时子进程退出; /D选项将disable auto-run脚本 (可选);

这么做的原因是: 防止command prompt窗口被自动关闭 – 被EXIT命令退出; EXIT命令会自动关闭command prompt窗口, 除非它是在command prompt的子进程中调用的. 窗口被关闭挺烦人的, 因为你来不及看脚本所输出的信息.

Comments

官方定义了 REM(Remark)关键字:

REM This is a comment!

power user方法是使用::, 这是利用两个lable操作符:的hack方式

多数人发现::比起REM来不那么容易分心; 不过要注意有几个地方’::’会造成error.

:: This is a comment too!! (usually!)

e.g. FOR循环会对 ::风格的注释输出error. 简单的回退方案是使用REM

Silencing Display of Commands in Batch Files

第一行非注释的batch命令一般是关闭打印(ECHO)

 @ECHO OFF

@是个特殊操作符, 用来抑制command line中的打印; 一旦将 ECHO设为off, 就不再需要 @操作符了.

恢复命令行打印:

ECHO ON

在退出脚本前, command prompt会自动恢复ECHO的上个状态.

Debugging Your Scripts

batch有许多的 trial和 error coding. 可惜这里没有 WIndows batch script的 debugger(调试器). 更糟的是, 这里也没有将 command processor放入 verbose state来帮助troubleshoot 的方法 (这是Unix/Linux脚本的通用技术).

使用ECHO打印自定义的ad-hoc(专门)信息可能是唯一的选择; 进阶的脚本开发者可以使用一些trickery来选择性地打印信息, 不过还是建议在脚本功能完善的时候把 debugging/instrumentation 代码移除掉.

Part 2 – Variables

变量, 在一个non-trivial batch程序中是必须的; 变量的语法会有些奇怪;

Variable Declaration

DOS无需声明变量. 未声明/未初始化的变量是个空的string, 或者"". 多数人喜欢这个, 因为可以减少代码量; 不过这样也容易出傻bug, 比如变量名有typo(type error打印错误);

Variable Assignment

SET命令将值赋给变量

SET foo=bar

NOTE:不要在名字和之间加入whitespace; SET foo = bar无法工作;

/A可以在赋值时打开arthimetic支持; 这个工具很有用, 可以检验用户输入是否是个数字值;

SET /A four=2+2
4

一般的约定是给变量使用小写名字; 系统级别的变量, 比如环境变量, 使用大写名字; 这些环境描述符指示了系统中某些东西的地址, e.g. %TEMP%是临时文件的目录;

DOS是大小写敏感的, 因此约定虽然没有强制, 但最好是这么配置, 让阅读和调试简单些.

WARNING: SET总是会覆盖(clobber)任何已有的变量; 在写脚本的时候最好先检验一下是否会将系统级别的变量覆盖; 快速方法是 ECHO %foo%, 确认 foo不是个已有变量;

e.g. 你可能想命名一个”temp”变量, 但并不想要改变环境变量“%TEMP%”; DOS包含一些”dynamic”环境变量, 它们更像是命令; 这些dynamic变量包含 %DATE%, %RANDOM%, %CD%; 覆盖这些dynamic变量是个糟糕的主意;

Reading the Value of a Variable

大多数情况下你可以用 %<var>%来读取变量的值; 下面的例子在console中打印出foo变量的当前值:

C:\> SET foo=bar
C:\> ECHO %foo%
bar

有些特殊情况变量不使用%语法;

Listing Existing Variables

不带参数的 SET命令会将当前command prompt会话中的所有变量打印出来; 其中多数是系统级别的环境变量, 如 %PATH% ,%TEMP%.

NOTE: 调用 SET会列出当前对话中所有的 regular(static)变量; 列表中包含 dynamic环境变量如 %DATE%, %CD%; 可以通过SET的帮助文档来查看这些dynamic环境变量: 调用 SET /?.

Variable Scope (Global vs Local)

默认情况下, 变量对于整个command prompt会话来说是global的; 调用 SETLOCAL目录来使得变量对于脚本来变成local; 调用 SETLOCAL后, 变量的赋值会在调用 `ENDLOCAL’, ‘EXIT’或者执行到达脚本的EOF(end of file)之后被revert(恢复);

下例演示了改变一个已有变量名foo, 脚本为 HelloWorld.cmd; shell在HelloWorld,cmd退出时恢复变量%foo%的原始值;

>TYPE HelloWorld.cmd
SETLOCAL
SET v=Local Value
ECHO v=%v%

>SET v=Global Value
>ECHO v=%v%
v=Global Value

>HelloWorld.cmd
>SETLOCAL
>SET v=Local Value
>ECHO v=Local Value
v=Local Value

>ECHO v=%v%
v=Global Value
>

真实世界中的例子可能会是一个修改系统级别%PATH%环境变量的脚本,

>TYPE LocalPath.cmd
SETLOCAL
SET PATH=%SystemRoot%\system32
ECHO %PATH%

>ECHO %PATH%
REM Original %PATH%
"C:\Windows\system32;C:\Windows\System32\WindowsPowerShell\v1.0\"

>LocalPath.cmd
>SETLOCAL
>SET PATH=%SystemRoot%\system32
>ECHO %PATH%
REM %PATH% modified locally
"C:\Windows\system32"

>ECHO %PATH%
REM Original %PATH% restored
"C:\Windows\system32;C:\Windows\System32\WindowsPowerShell\v1.0\"

Special Variables

有少数特殊情况下变量工作起来有些不同; 在command line上传递给脚本的参数也是变量, 然而, 却不使用 %var%语法;

代替的是: 使用单个%带数字0-9来读取每个参数, 每个数字依次代表参数的位置; 在随后的bacth脚本中可以看到一个创建function/subroutine的hack方式有一样的风格;

还有些变量语法使用 !, !var; 这是个调用delayed expansion(延迟扩展)的特殊情况; 在后面讨论 condition(if/then)和looping的时候可以了解更多细节;

Command Line Arguments to Your Script

通过特殊语法可以读取传递给脚本的command line参数;

语法: 单个%字符后面跟参数的位置0-9; zero顺位参数是batch文件的名称; 因此脚本HelloWorld.cmd中变量%0代表”HelloWorld.cmd”;

command line参数:

- %0 脚本/程序名, 总是个非空值

- %1 第一个command line参数, 如果参数没提供, 就为空;

- %2 第二个command line参数, 如果参数没提供, 就为空;

- …

- %9 第九个参数

NOTE: DOS支持超过9个command line参数, 不过你无法直接读取第10个或更多的参数; 因为特殊变量语法不支持 %10或更多; 事实上, shell会将 %10 读作 %0 的后缀 –> sting “0”;

使用 SHIFT目录将第一个参数从参数列表中pop出去, 这样就把所有的参数左移一格; e.g. 第二个参数从位置 %2移到 %1, 这样第10个参数就成了 %9;

后面会看到如何在循环中处理大量的参数;

Tricks with Command Line Arguments

Command Line Arguments也支持一些有用的可选语法, 在command line参数是文件名的时候, 对其运行quasi-macros(类似宏)的操作;

这些 marco被称为 变量substitution support, 可以从command line参数中解析path, timestamp, 或者file size;

对于这个超有用的特性来说文档有些难找 – 运行 FOR /?来查看.

  • %~1对第一个command line参数移除quotes(引号), 这个在参数作为文件路径时很有用; 你会需要在文件路径上加上引号, 但是, 在一个文件路径上两次加上引号会造成 file not found error.

    SET myvar=%~1

  • %~f1 是第一个参数的folder(文件夹)的全路径
  • %~fs1 和上面的一样, 但是多出来的 s选项 yield出 DOS 8.3 short name path到第一个参数中; (e.g. C:\PROGRA~1是常用的8.3 short name变体 – 对于 C:\Program Files)

    在使用第三方脚本或程序的时候这很有用, 这样就无需处理文件路径中的空格了;

  • %~dp1是第一个参数的 parent folder的全路径; 在每个测试脚本文件自身位置的batch文件中都可以用这个trick;

    语法 SET parent=%~dp0 会将脚本的 folder的路径放入变量 ‘%parent%’.

  • %~nx1 代表第一个参数中的文件名以及文件后缀名; 可以用来在运行时检测脚本的名字; 如果需要将信息打印出来, 可以给消息加上脚本名称的前缀: e.g. ECHO %~n0: some message 代替 ECHO some message;

    这里的前缀可以帮到终端用户, 可以知道输出是从脚本打印而不是另一个脚本调用的程序所打印的; 要是花几个小时来追踪一个脚本生成的obtuse error message的话, 其实是挺蠢的. 这是从 Unix/Linux世界中学到的一招改进;

Some Final Polish

在batch脚本顶部加入

SETLOCAL ENABLEEXTENSIONS
SET me=%~n0
SET parent=%~dp0

SETLOCAL命令确保在脚本退出时就不会再clobber已有变量; ENABLEEXTENSIONS参数启用一个很有用的特性, 称为 command processor extension;

%me%中保存的是脚本名(不包括文件后缀); 可以给打印的message加上前缀 (e.g. ECHO %me%: some message)

%parent%中存储的是脚本的parent path(父路径); 可以用来给当前脚本相同目录下的文件提供 fully qualified filepath.

Part 3 – Return Codes

return code是和脚本外部的执行者进行交流的正确方法; 可惜的是很多Windows开发者都忽视了它.

Return Code Conventions

根据约定, 当执行成功, command line execution应该返回 zero, 而执行失败则返回 non-zero; Warning message则不影响return code.

Checking Return Codes In Your Script Commands

环境变量%ERRORLEVEL%包含了最后执行的程序或脚本的 return code; 一个有用的特性: built-in的 DOS命令如 ECHO, IF, SET 会保留现有的 %ERRORLEVEL%的值;

检查 non-zero return code的conventional technique(传统方法)是在 IF命令中使用 NEQ(Not-Equal-To)操作符;

IF %ERRORLEVEL% NEQ 0 (
  REM do something here to address the error
)

另一个通用的方法:

IF ERRORLEVEL 1 (
  REM do something here to address the error
)

当return code是任何数字–等于1或大于1时, ERRORLEVEL 1 语句为true;

不过程序返回正数的同时也有可能返回负数, 这时候这个语句就会有问题;

大多程序不会描述每个可能的return code, 因此最好是显式地检查 non-zero: NEQ 0风格, 而不要假设 return code在error时会是1或大于1;

一些特殊的error code. e.g. 测试一个可执行程序或脚本是在你的PATH中, 调用程序然后检查 return code 9009;

SomeFile.exe
IF %ERRORLEVEL% EQU 9009 (
  ECHO error - SomeFile.exe not found in your PATH
)

不是多查看trial和尝试error的话很难预先了解到这些特殊用法; 记住, 这是 duct tape programming. 它不总是很漂亮, 但可以完成工作;

Conditional Execution Using the Return Code

这里有个超赞的shorthand(便利方法)用来基于第一个命令的成功或失败, 执行第二个命令; 第一个程序/脚本必须遵从成功返回0, 失败返回non-0的规则;

要在成功后执行一个 follow-on(跟随)命令, 使用 && 操作符;

SomeCommand.exe && ECHO SomeCommand.exe succeeded!    

要在失败后执行一个 follow-on命令, 使用 || 操作符;

SomeCommand.exe || ECHO SomeCommand.exe failed with return code %ERRORLEVEL%

和面向对象中的 &&, || 操作符不同, 0 && xxx 竟然是执行xxx, non-0 || xxx 竟然是执行 xxx; 而且 0 || xxx不执行后面的, non-0 && xxx也不执行后面的… 简直是反过来的短路规则

这项技术可以用来在发生错误的时候halt(叫停)脚本; 默认情况下, command processor会在error出现的时候继续执行; 为了实现 halt on error(错误时中止), 不得不要进行编码;

一个halt on error的简单方案是使用 带 /B switch(开关)的 EXIT命令(退出当前的batch脚本内容, 而不是command prompt process);

如果是从外部执行batch脚本, 则还是会退出CMD.exe;

还要从失败的命令中返回一个特定的 non-zero return code来通知调用者:

SomeCommand.exe || EXIT /B 1

类似的方法还有使用 隐式的 GOTO lable :EOF (End-Of-File); 这样跳到EOF可以退出当前脚本, 并且return code为 1;

SomeCommand.exe || GOTO :EOF

Tips and Tricks for Return Codes

推荐成功的 return code都为 zero, 对于 DOS batch文件都返回正值; 正值是因为调用者可能会使用 IF ERRORLEVEL 1 语法来检测脚本;

另外建议给可能的return code都加上文档, 在脚本头上使用便于阅读的 SET语句:

SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_FILE_NOT_FOUND=2

注意这里打破了之前的约定, 使用了大写的变量名 – 这是想表示这些变量是常量, 而且在任何地方都不该被修改; DOS不像 Unix/Linux shell那样可以支持常量值, 这挺糟糕的.

Some Final Polish

一个小小的优化: 按2的幂次定义 return code;

SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_FILE_NOT_FOUND=2
SET /A ERROR_FILE_READ_ONLY=4
SET /A ERROR_UNKNOWN=8

这样就可以有更多灵活性: 使用 bitwise OR(按位或)多个 error number, 可以在一个error code中记录多个问题; 这在interactive(交互式)的情况下很少用到, 但在编写脚本时, 如果你缺乏对目标系统的权限, 就会非常有用;

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS

SET /A errno=0
SET /A ERROR_HELP_SCREEN=1
SET /A ERROR_SOMECOMMAND_NOT_FOUND=2
SET /A ERROR_OTHERCOMMAND_FAILED=4

SomeCommand.exe
IF %ERRORLEVEL% NEQ 0 SET /A errno^|=%ERROR_SOMECOMMAND_NOT_FOUND%

OtherCommand.exe
IF %ERRORLEVEL% NEQ 0 (
    SET /A errno^|=%ERROR_OTHERCOMMAND_FAILED%
)

EXIT /B %errno%

如果 和 都失败了, return code会是 0x2和 0x4的bitwise combination(按位组合), 或者是数字6; 这个 return code告知我们两个 error都出现了; 更进一步, 可以用相同的 error code反复地调用 bitwise OR, 仍然可以解读到哪些 error出现过.

Part 4 – stdin, stdout, stderr

DOS, 就像 Unix/Linux, 使用三个universal “”files” - keyboard input(键盘输入), printing text on screen(屏幕字符输出), printing errors on screen(屏幕错误输出);

“Standard In(标准输入)”文件–stdin, 包含程序/脚本的输入;

“Standard Out(标准输出)”文件–stdout, 用来将输入写到屏幕显示;

“Standard Err(标准错误)”文件–stderr, 包含显示到屏幕上的错误消息;

File Numbers

对于这三个标准文件, 作为standard stream(标准流), 使用数字 0,1,2来引用; stdin是 file 0, stdout是 file 1, stderr是 file 2;

Redirection

batch文件的一个任务是将程序的输出传到 log文件; >操作符send(传送), 或者 redirect(重定向) stdout或 stderr到另一个文件;

e.g. 可以将当前目录结构列表写入文件:

DIR > temp.txt

>操作符会使用从 DIR命令返回的 stdout覆盖 temp.txt的内容; >>操作符是个slight variant(轻量级变量), 它把输出 append到目标文件, 而不是覆盖目标文件.

一个通用的技术是使用 >来创建/覆盖 log文件, 然后使用 >> 在之后append到 log文件中.

SomeCommand.exe   > temp.txt
OtherCommand.exe >> temp.txt

默认情况下, >>>操作符重定向 stdout. 可以在操作符前面使用文件编号 2来重定向 stderr:

DIR SomeFile.txt  2>> error.txt

甚至还可以用文件编号和 &前缀来结合stdout和stderr流:

DIR SomeFile.txt 2>&1

如果想要把 stdout和 stderr都写入同一个文件时这很有用.

DIR SomeFile.txt > output.txt 2>&1

要将文件内容作为一个程序的输入, 代替手动一个个字地从键盘输入, 可以用 <操作符:

SORT < SomeFile.txt

—TBC—

—YCR—

时间: 2024-10-29 19:36:44

Windows Batch 1-4的相关文章

Build step &#39;Execute Windows batch command&#39; marked build as failure

坑爹的Jenkis,在执行windows命令编译.NET项目的时候命令执行成功了,但是却还是报了这样一个错: Build step 'Execute Windows batch command' marked build as failure 综合了几个stackoverflow上的答案,原因如下: jenkins执行windows命令,若退出代码不为0 ,则jenkins会将构建标记为失败 我解决的方法:在bat脚本最后一行加上 exit 0 Build step 'Execute Windo

CCNET+ProGet+Windows Batch搭建全自动的内部包打包和推送及管理平台

所要用的工具: 1.CCNET(用于检测SVN有改动提交时自动构建,并运行nuget的自动打包和推送批处理) 2.ProGet(目前见到最好用的nuget内部包管理平台) 3.Windows Batch(windows的批处理,用于nuget的自动打包和推送)(这里是最难解决的地方) 具体的搭建步骤: 一.先搭建CCNET的持续集成环境,可以参照以下这些文章: http://www.cnblogs.com/jillzhang/archive/2008/03/03/1089099.html htt

深入浅出Windows BATCH

1.什么是Windows BATCH BATCH也就是批处理文件,有时简称为BAT,是Windows平台上的一种可运行脚本,与*nix(Linux和Unix)上的Shell脚本和其它的脚本(Perl,Python)等是一样的,实质上就是一个文本文件,可是用特定的软件去解释的时候,就变成了可运行脚本.在Windows上,可运行脚本就是BATCH文件,也叫批处理文件,这是从DOS时代遗留下来的名字,意思就是把非常多命令放到一起来运行.它的扩展名是*.bat,双击便可直接运行,在命令行(CMD或叫做命

windows batch语法

windows BATCH基本知识扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的文件就是批处理文件. ==== 注 =======================================.bat是dos下的批处理文件.cmd是nt内核命令行环境的另一种批处理文件从更广义的角度来看,unix的shell脚本以及其它操作系统甚至应用程序中由外壳进行解释执行的文本,都具有与批处理文件十分相似的作用,而且同样是由专用解释器以行为单位解释执行,这种文本形式更通用的称谓是脚本语

jenkins 如何处理windows batch command

这两天一直被一个问题困扰. 在jenkins的windows batch command 测试好的,拿到bat文件中,再从Execute Windows Batch command 中调用这个bat,竟然离奇的报错了. 为什么呢? 先介绍一下场景和代码的逻辑.测试好的代码: CD %ROOTPATH%.\Tools\Bin\Python26\python. exe .\Tools\PythonScripts\SendMail.py %AUTOBUILD_PATH%\Charts [email p

Windows Batch 4-10

Suppressing Program Output pseudofile(伪文件)NUL是用来丢弃程序的输出的. e.g. 通过针对 loopback address调用 ping, 模拟Unix命令 sleep. 通过将 stdout重定向到 NUL设备来防止将 output打印到command prompt屏幕上. PING 127.0.0.1 > NUL Redirecting Program Output As Input to Another Program 假设你想要将程序的out

Jenkins+ProGet+Windows Batch搭建全自动的内部包(NuGet)打包和推送及管理平台

这一篇文章是继http://www.cnblogs.com/EasonJim/p/5954155.html的升级版,由于CCNET已经过程,所以我把打包过程的CCNET工具换成Jenkins去实现,批处理那些也没有改变. 同时这也是全程批处理的操作实践. 阅读时,请参考上一篇的实现思路. 一.配置 1.新建Job 注意:上面选择为[构建一个自由风格的软件项目] 2.填写项目信息 3.配置SVN获取源码 这里默认这样选择,只有更新时才会去触发下一步操作. 4.配置构建触发的时间 这里是每分钟进行s

Windows Batch Scripts

Some simple examples: simple.bat @echo off set _var1=3 set _var2=5 set /a _result=%_var1%+%_var2% echo Result is %_result% mult.bat @echo off if "%1" == "" goto :help if "%2" == "" goto :help set /a result=%1 * %2 e

Windows批处理(cmd/bat)常用命令小结

转载自:“趣IT”微信公共号 前言 批处理文件(batch file)包含一系列 DOS命令,通常用于自动执行重复性任务.用户只需双击批处理文件便可执行任务,而无需重复输入相同指令.编写批处理文件非常简单,但难点在于确保一切按顺序执行.编写严谨的批处理文件可以极大程度地节省时间,在应对重复性工作时尤其有效. 在Windows中善用批处理可以简化很多重复工作 什么是批处理 批处理(Batch),也称为批处理脚本.顾名思义,批处理就是对某对象进行批量的处理.批处理文件的扩展名为bat. 目前比较常见