目录
在windows上编程或者制作一些小工具,少不了使用批处理脚本,而且在各种开发环境搭建中我们经常会看到批处理脚本。批处理脚本以cmd命令为基础,增加一些变量和参数构造多命令来完成复杂的任务。
echo就是跟所有语言相似的输出打印命令,一般我们会在前面加上@前缀,表示不会显示打印语句。
C:\Users\buejee\Desktop\battutorial>for %i in (1,3,5) do echo %i
C:\Users\buejee\Desktop\battutorial>echo 1
1
C:\Users\buejee\Desktop\battutorial>echo 3
3
C:\Users\buejee\Desktop\battutorial>echo 5
5
C:\Users\buejee\Desktop\battutorial>for %i in (1,3,5) do @echo %i
1
3
5
我们也会调用@echo off关闭显示打印信息,这样后面的所有echo就不用加@前缀来隐藏命令。
C:\Users\buejee\Desktop\battutorial>type bat_echo.bat
echo hello
@echo off
echo world
C:\Users\buejee\Desktop\battutorial>bat_echo.bat
C:\Users\buejee\Desktop\battutorial>echo hello
hello
world
在这个示例中,第一次没有设置@echo off,运行脚本,回显了echo hello,但是当运行echo world的时候,它没有回显,因为已经关闭了回显。
echo表示输出,那么输入怎么办?这里要借助一个小技巧set /p
@echo off
echo please input you name:
set /p name=
echo your name is : %name%
运行:

echo还可以结合>与>>命令向文件中写入和追加内容。
C:\Users\buejee\Desktop\battutorial>echo hello > hello.txt
C:\Users\buejee\Desktop\battutorial>echo world >> hello.txt
C:\Users\buejee\Desktop\battutorial>type hello.txt
hello
world
C:\Users\buejee\Desktop\battutorial>echo hello,world > hello.txt
C:\Users\buejee\Desktop\battutorial>type hello.txt
hello,world
C:\Users\buejee\Desktop\battutorial>
其实这个示例里面隐含了一个操作,就是如果hello.txt文件不存在就创建,存在就覆盖或者追加。在linux下,我们新建一个文件可以使用touch命令,在windows命令行下,创建文件可以使用echo > xxx.txt 就可以了。
值得一提的是,因为cmd命令行默认编码是ANSI(936),而批处理脚本默认编码是UTF8(65001),所以在bat文件中使用echo输出中文会乱码。解决办法:要么改变cmd编码,要么改变脚本编码为ANSI。

改变脚本编码,可以在notepad++里面直接使用 "编码" 菜单项:转为 ANSI 编码 修改,再一个办法就是通过记事本打开脚本,然后“另存为”的时候选择编码 ANSI,如下所示:

任何语言都有注释,批处理脚本语言也不例外,它的注释,就是使用关键字REM,一般带上@前缀。

在这个图中,可以看到,当使用REM关键字的时候,这一行内容就已经变为绿色高亮,明显与可以执行的语句有区别。
| windows命令行 | 功能描述 | linux终端 |
| cd | 切换工作目录 | cd |
| dir | 列出当前文件夹下所有文件 | ls [-lh] |
| type | 查看文件内容 | cat |
| md/mkdir | 创建目录 | mkdir |
| del | 删除文件 | rm |
| rd | 删除目录 | rm -r |
| copy/xcopy | 拷贝 | cp [-r] |
| cls | 清屏 | clear |
| findstr | 根据关键字查找 | grep |
| move/rename | 移动/重命名 | mv/rename |
| tasklist | 查找进程 | ps [-ef] |
| taskkill | 杀死进程 | kill [-9] |
在执行脚本的时候,我们可以在脚本后面跟上一些参数,这些参数我们在脚本中通过%1、%2、%3、%4依此类推类获取。
@echo off
@echo first param is %1
@echo second param is %2
@echo third param is %3
@echo fourth param is %4
运行脚本,打印如下:
C:\Users\buejee\Desktop\battutorial>bat_params.bat hello world 3 4
first param is hello
second param is world
third param is 3
fourth param is 4
bat脚本参数只能表示%1~%9,也就是最多可以表示出9个参数。
从这个脚本显示的样子可以看出,当表示%10的时候,其实已经无法表示了,只是表示%1后面拼接了一个0,所以第十个参数是10,第十一个参数是11,第十二个参数是12。
C:\Users\buejee\Desktop\battutorial>bat_params.bat 1 2 3 4 5 6 7 8 9 9 9 9
first param is 1
second param is 2
third param is 3
fourth param is 4
fifth param is 5
sixth param is 6
seventh param is 7
eighth param is 8
ninth param is 9
tenth param is 10
eleventh param is 11
twelfth param is 12
解决办法就是需要将前面的参数弹出。使用shift /1
代码:
@echo off
@echo first param is %1
@echo second param is %2
@echo third param is %3
@echo fourth param is %4
@echo fifth param is %5
@echo sixth param is %6
@echo seventh param is %7
@echo eighth param is %8
@echo ninth param is %9
shift /1
@echo tenth param is %9
shift /1
@echo eleventh param is %9
shift /1
@echo twelfth param is %9
运行结果:
C:\Users\buejee\Desktop\battutorial>bat_params.bat 1 2 3 4 5 6 7 8 9 100 101 199
first param is 1
second param is 2
third param is 3
fourth param is 4
fifth param is 5
sixth param is 6
seventh param is 7
eighth param is 8
ninth param is 9
tenth param is 100
eleventh param is 101
twelfth param is 199
变量赋值与取值:
变量赋值语句使用“=”,且“=”两边没有空格。 取值的时候使用%%包裹,这个跟我们在命令行下打印系统环境变量的值一样:echo %JAVA_HOME%
在bat脚本中,for循环的变量,我们需要使用两个%%来表示,在cmd命令行下,可以使用一个%表示:
bat_variable_in_forloop.bat
@echo off
for %%i in (1,2,3,5) do (
@echo %%i
)
运行:

以上这些都是自定义变量,还有一些系统内置的变量,可以方便我们在脚本中使用:
%cd% 当前目录
%os% 操作系统名称
%date% 系统日期
%time% 系统时间
%username% 当前用户名

在操作脚本的时候,想要得到脚本相关的参数:比如脚本属性、所在盘符、全路径名、文件名、 路径、缩写路径、文件最后修改时间、扩展名、文件大小、带盘符路径。就需要用到如下的变量:%~(a|d|f|n|p|s|t|x|z|dp)0。示例如下:
bat_builtin_variable.bat
@echo off
@REM attribute
@echo attr : %~a0
@REM drive name
@echo drive : %~d0
@REM filename
@echo filename : %~f0
@REM name
@echo name : %~n0
@REM path
@echo path : %~p0
@REM short name
@echo shortname : %~s0
@REM time(modify)
@echo time : %~t0
@REM extension name
@echo extensionname : %~x0
@REM size
@echo size : %~z0
@REM drive name + path
@echo dp : %~dp0
运行结果如下:

从中可以看出,name没有扩展名后缀.bat,path没有盘符c:,所以一般使用%~dp0来表示脚本路径。 缩写这里,如果一个文件夹名称不超过6个字符,则使用原样名称,只有文件名称超过6个字符,才使用缩写,而且缩写的名称会变大写。
for循环的语法是:
for [/d/l/r/f] %%i in () do (
)
这里可以根据场景选择不同的参数:
/d 表示获取某一目录下的所有文件夹
@echo off
for /d %%i in (%cd%\*) do (
@echo %%i
)
运行结果:

/l 可以使用一个序列来做循环,比如 (1,2,10)表示从1开始,10结束,步长为2,产生的序列为:(1,3,5,7,9)。(5,-1,1),表示从5开始,1结束,步长为-1,也就是递减数列(5,4,3,2,1)。
@echo off
for /l %%i in (1 2 10) do (
echo %%i
)
运行结果:

/r 可以获取某一个目录下所有的文件以及文件夹下的文件
@echo off
for /r %%i in (*.txt) do (
@echo %%i
)
该脚本的意思是读取当前文件夹以及子文件夹下的所有.txt扩展名的文件。与/d遍历当前文件夹下的文件夹不同, 它不止遍历当前文件夹,还遍历子文件夹。
运行结果:

/f 读取文件
@echo off
for /f %%a in (user.txt) do (
echo %%a
)
运行结果:

我们准备的文件,user.txt里面是id,name,age三列按空格分割的五行数据,最后只读到了id这一列,因为/f默认是按照空格分隔来读取每一行第一列内容。
可以增加一个"delims="的参数,表示不分割读取每一行。
@echo off
for /f "delims=" %%a in (user.txt) do (
echo %%a
)
运行结果:

还可以分割,并取分割之后的某几列,增加tokens参数:比如"tokens=1-3 delims= "表示按照空格分隔,取1到3列,也就是所有列,但是每一列在取的时候,需要按照%%a,%%b,%%c依次类推来取值。
@echo off
for /f "tokens=1-3 delims= " %%a in (user.txt) do (
echo %%a - %%b - %%c
)
运行结果:

/f 这里不仅可以读取文件,还可以用来读取系统命令执行的结果。
@echo off
for /f "usebackq tokens=1-5 delims= " %%a in (`netstat -aon^| findstr 135`) do (
@echo %%a - %%b - %%c - %%d - %%e
)
这段脚本读取netstat -aon | findstr 135的结果,并按照空格分隔,取1-5列。
运行结果:

bat脚本里面的函数定义:采用冒号开头,然后定义函数名。在调用的时候,使用关键字call,同样的要跟上冒号:函数名。
bat脚本有个特点,它虽然可以定义函数,因为脚本串行执行的特点,如果没有跳转指令控制的话,函数定义也会被当作指令执行,虽然函数没有被调用。
如下所示的代码,我们定义了hello、world两个函数,我们只调用了world函数,但是最后运行结果很诡异:
@echo off
call :world
:hello
@echo hello
goto :eof
:world
@echo world
goto :eof
运行结果:
C:\Users\buejee\Desktop\battutorial>bat_func_test.bat
world
hello
要想让上面的代码执行正确,我们需要在call :world函数之后增加 goto :eof的跳转控制:

call除了可以调用函数之外,还可以调用其他脚本。
和其他语言一样,数组在bat脚本中,可以直接通过set 命令设置,如下所示:
@echo off
set arr=1,3,5,7,9
for %%a in (%arr%) do (
@echo %%a
)
运行结果:

这种方式定义的数组,却无法通过下标访问,它虽然可以通过for循环遍历并得到数组中的所有元素,但是却不能称为普通意义上的数组。这种一次性声明的数组,只能是一个类数组。
在批处理脚本中,可以通过下标访问的数组,需要这样来定义:
@echo off
setlocal enabledelayedexpansion
set a[0]=1
set a[1]=3
set a[2]=5
set a[3]=7
set a[4]=9
set a[5]=11
for /l %%n in (0,1,5) do (
@echo !a[%%n]!
)
运行结果:

这种数组,虽然可以通过下标访问,但是无法知道它的长度,在进行遍历的时候,我们不得不写死范围。可以通过如下的方式计算数组长度:
@echo off
set Arr[0]=1
set Arr[1]=2
set Arr[2]=3
set Arr[3]=4
set Arr[4]=5
set "x=0"
:loop
if defined Arr[%x%] (
set /a "x+=1"
goto loop
)
echo the length is %x%
运行结果:

=======================================================
批处理脚本与cmd命令行密切相关,所有在脚本中能够执行的操作,基本都可以在命令行下执行,但是有时候,命令行与脚本也有少许差别,比如在命令行下的for循环中,变量可以直接使用一个%来表示,但是脚本中必须使用两个%%来表示。
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我有一个在Linux服务器上运行的ruby脚本。它不使用rails或任何东西。它基本上是一个命令行ruby脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
有没有一种简单的方法可以判断ruby脚本是否已经在运行,然后适本地处理它?例如:我有一个名为really_long_script.rb的脚本。我让它每5分钟运行一次。当它运行时,我想看看之前运行的是否还在运行,然后停止第二个脚本的执行。有什么想法吗? 最佳答案 ps是一种非常糟糕的方法,并且可能会出现竞争条件。传统的Unix/Linux方法是将PID写入文件(通常在/var/run中)并在启动时检查该文件是否存在。例如pid文件位于/var/run/myscript.pid然后你会在运行程序之前检查它是否存在。有一些技巧可以避免
我正在开发一个Ruby脚本,需要在没有Ruby解释器的情况下部署到系统上。它将需要在使用ELF格式的FreeBSD系统上运行。我知道有一个ruby2exe项目可以编译在Windows上运行的ruby脚本,但是在其他操作系统上这样做容易吗?甚至可能吗? 最佳答案 您是否检查过Rubinius或JRuby是否允许您预编译您的代码? 关于ruby-ruby脚本可以预编译成二进制文件吗?,我们在StackOverflow上找到一个类似的问题: https://
我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby-vips的github页面上的链接,我们将不胜感激!如果有ruby-
我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d
我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。