我的GitHub | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目录
目录
常用功能
判断字符串中是否包含子串
方式一
echo %1 | findstr %2 >nul && echo yes || echo no
:: 加了 >nul 就可以不打印 echo 的内容
方式二
@echo off & setLocal EnableDelayedExpansion
set str=%1
if not "x!str:%2=!"=="x%str%" (
echo Y
) else (
echo N
)
将命令的结果赋值给变量
例如,命令git rev-parse --abbrev-ref HEAD
可以获取当前分支的分支名,那么如下方式可以将此值赋给变量(注意,以下命令只提取命令结果中的第一行内容):
for /f "delims=" %%i in ('git rev-parse --abbrev-ref HEAD') do set branch=%%i
echo 子仓的分支名:%branch%
for /f "delims=" %%j in ('reg query "HKEY_LOCAL_MACHINESOFTWAREJavaSoftJava Development Kit1.8" /v JavaHome') do set java=%%j
echo %java%
休眠指定时间
set /a second=5
echo %time%
ping -n %second% 0.0.0.0 1>nul 2>nul
echo %time%【-1秒】
w32tm /stripchart /computer:localhost /period:1 /dataonly /samples:%second% >nul 2>&1
echo %time%【-1秒】
typeperf "SystemProcessor Queue Length" -si %second% -sc 1 >nul
echo %time%【+1秒】
0:20:16.01
0:20:20.11
0:20:24.23
0:20:30.49
替换文件内容
@echo off & setlocal EnableDelayedExpansion
SET filename=%1
SET originStr=%2
SET newStr=%3
:: 读取文件filename所有内容
for /f "delims=" %%a in (%filename%) do (
set str=%%a
set str=!str:%originStr%=%newStr%!
echo !str!>>$ %把修改后的全部行存入$中%
)
:: 用$的内容替换原来filename内容
move $ %filename%
时间、日期解析
@echo off
:: gets time using typePerf command
:: with put some effort to be made fast and maximum compatible
setlocal
::check if windows is XP and use XP valid counter for UDP performance
if defined USERDOMAIN_roamingprofile (set "v=v4") else (set "v=")
set "mon="
for /f "skip=2 delims=," %%# in ('typeperf "UDP%v%*" -si 0 -sc 1') do (
if not defined mon (
for /f "tokens=1-7 delims=.:/ " %%a in (%%#) do (
set mon=%%a
set date=%%b
set year=%%c
set hour=%%d
set minute=%%e
set sec=%%f
set ms=%%g
)
)
)
echo %year%.%mon%.%date%
echo %hour%:%minute%:%sec%.%ms%
endlocal
goto eof 的作用
eof 是end of file
的缩写,在批处理作用主要有二:
- 在无
call
的情况下,会直接退出批处理
,此时等同于exit /b 0
- 在有
call
的情况下,会中止call
,继续执行其他命令
call :testgoto
echo 3
:testgoto
echo 1
goto :eof
echo 2
:: 在有`call`的情况下,会`中止call`,继续执行其他命令【1-3-1】
:: 在无`call`的情况下,会直接`退出批处理`,此时等同于`exit /b 0`【1】
和 java 混合编程
模板一
@Deprecated /*********************************** >nul 2>&1
@echo off
java -version >nul 2>&1 || (
echo java not found
exit /b 1
)
set javaFile=Test
copy %~f0 %javaFile%.java >nul 2>&1
javac %javaFile%.java
java %javaFile% %*
del %javaFile%.java %javaFile%.class >nul 2>&1
exit /b 0
**************************************************************/
public class Test {
public static void main(String[] args) {
//注意:①必须使用类的全路径,而不能导包②请使用GBK编码格式,不要用utf-8
System.out.println("参数为:"+java.util.Arrays.toString(args));
}
}
$ testJava.bat 参数1 参数2
参数为:[参数1, 参数2]
模板一语法分析
首先作为批处理脚本来执行
@
表明不回显接下来的这个命令Deprecated
表明是要执行这个命令,但是因为不存在这个命令,所以实际上会提示:'Deprecated' 不是内部或外部命令,也不是可运行的程序或批处理文件。
- 接下来的
/**
被当做是Deprecated
命令的参数,命令不存在的情况下,参数也是无意义的 - 接下来的
>nul 2>&1
表明是将标准输出和标准错误输出重定向到nul
,所以交过就是不打印上面的那个错误提示 - 接下来是几行正常的bat命令
set javaFile=Test
设置临时生成的类名,注意需和下面定义的类名一致copy %~f0 %javaFile%.java >nul 2>&1
将此bat文件复制一份内容,并更名为Test.java
- 然后通过
javac
命令可以将Test.java
编译成Test.class
文件 - 然后通过
java
命令便可执行上述生成的Test.class
文件 - 最后删除临时生成的这两个文件
- 执行到
exit /b 0
后bat结束
然后分析作为Java类来编译时的语法
- 作为Java类编译时,
@Deprecated
是Java中类的注解,可以放在Java文件的最开始的位置,在Java中含义是:不建议使用、废弃 - 接下来的
/**
和**/
之间的部分全部被当做注释 - 加下来就是完整的Java语法的程序了,这里可以写任意合法的Java程序
- 需要注意的是,如果需要导包,需要保证
import
语句放在文件头,不然会报错(放文件头有一个不太好的体验就是:在bat中执行时会有错误提示)
模板二
import java.text.SimpleDateFormat; // >nul 2>&1
import java.util.Arrays; // >nul 2>&1
import java.util.Date; /* >nul 2>&1
@echo off
java -version >nul 2>&1 || (
echo java not found
exit /b 1
)
set javaFile=Test
copy %~f0 %javaFile%.java >nul 2>&1
javac %javaFile%.java
java %javaFile% %*
del %javaFile%.java %javaFile%.class >nul 2>&1
exit /b 0
**************************************************************/
public class Test {
public static void main(String[] args) {
System.out.println("
---------------------------请使用GBK编码格式,不要用utf-8----------------------------");
System.out.println("参数为:" + Arrays.toString(args));
System.out.println(new SimpleDateFormat("yyyy.MM.dd HH-mm-ss").format(new Date()));
}
}
$ testJava.bat 参数1 参数2
import java.text.SimpleDateFormat; // 1>nul 2>&1
import java.util.Arrays; // 1>nul 2>&1
import java.util.Date; /* 1>nul 2>&1
---------------------------请使用GBK编码格式,不要用utf-8----------------------------
参数为:[参数1, 参数2]
2020.06.19 00-29-05
模板三
批处理文件:
@echo off
echo --------------------------------------传递的参数------------------------------------
for %%i in (%*) do echo %%i
set javaFile=Test
javac %javaFile%.java || goto :EOF
java %javaFile% %* || goto :EOF
del %javaFile%.class >nul 2>&1 || goto :EOF
exit /b 0
Java类文件:
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class Test {
public static void main(String[] args) {
System.out.println("---------------------------请使用GBK编码格式,不要用utf-8----------------------------");
System.out.println("参数为:" + Arrays.toString(args));
System.out.println(new SimpleDateFormat("yyyy.MM.dd HH-mm-ss").format(new Date()));
}
}
输出:
$ testJava.bat 参数1 参数2
--------------------------------------传递的参数------------------------------------
参数1
参数2
---------------------------请使用GBK编码格式,不要用utf-8----------------------------
参数为:[参数1, 参数2]
2020.06.19 00-33-53
和 js 混合编程
案例:解析 json
使用方式:test.bat info.json name
参数分别为:json文件路径、要查找的key
@if (@CodeSection == @Batch) @then
@echo off & setlocal
cscript /nologo /e:JScript "%~f0" %*
goto :EOF
@end // end batch / begin JScript hybrid chimera
var htmlfile = WSH.CreateObject('htmlfile');
htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />');
var JSON = htmlfile.parentWindow.JSON;
var jsloc=WScript.Arguments.Item(0);
var jsonPath=WScript.Arguments.Item(1);
var txtFile=new ActiveXObject("Scripting.FileSystemObject").OpenTextFile(jsloc,1);
var json=txtFile.ReadAll();
var jParsed=JSON.parse(json);
var commond="JSON.stringify(jParsed."+jsonPath+")";
WScript.Echo(eval(commond));
htmlfile.close();
txtFile.close();
语法分析
语法分析 参考这里
- it's a type of
hybrid
batch-jscript. A batch file can be written in hybrid with VBS, jscript, HTA or even ini - If this file is run as Jscript, then since the if will fail, then the part between
@then
and@end
will not be executed, and the Jscript part will be executed. - If it's run as a batch file, then since (
@CodeSection
is not equal to@Batch
), the command@then
will not be executed, hence the commands following that line will be executed, eventually reachinggoto :eof
which jums over the remainder of the file.
白话解释:
- 首先以 batch 方式运行,由于
@if
中的条件为 false,所以不执行@then
- 然后会执行
@echo off & setlocal
- 然后会调用
cscript
命令,传过的参数为%~f0
,也即这个批处理命令自身,所以这一行的效果就是以 js 的方式执行当前脚本
- 以 js 的方式执行时,第一行的 if 语句为 false,所以 if 和 end 之间的命令不会执行
- 再往下面就全部是纯 js 代码了,所以后面就完全是以 js 的方式执行了
- 下面的 js 代码执行完毕后又回到了 batch 环境中
- 所以紧接着 batch 会执行
goto :EOF
语句,一行的含义是跳到末尾,也即结束运行,所以整个脚本结束了
模板
下面都是可以直接复用的模板,后面可以写任意js代码
@if (@CodeSection == @Batch) @then
@echo off & setlocal
cscript /nologo /e:JScript "%~f0" %*
goto :EOF
@end // end batch / begin JScript hybrid chimera
@if (@X)==(@Y) @end /* JScript comment
@echo off
cscript //E:JScript //nologo "%~f0" %*
exit /b %errorlevel%
@if (@X)==(@Y) @end JScript comment */
路径扩展
切换到当前脚本所在目录
切换到当前脚本所在目录:cd /d %~dp0
cd /d
是普通的更改目录命令,如果要改变驱动器,须带/D
开关%0
代表批处理本身~dp
是变量扩充,表示扩充到对应分区号的对应目录下- d 为
Drive
的缩写,即为驱动器、磁盘 - p 为
Path
缩写,即为路径、目录
- d 为
cd /d C:Android & pwd
cd /d %~dp0 & pwd
路径扩展语法
对于变量%n
(n为0-9的整数)及for里使用的%i
这样的变量,可以有以下的语法:
~n
:删除任何引号("),扩充 %n%~fn
:将 %n 扩充到一个完全合格的路径名
full%~dn
:仅将 %n 扩充到一个驱动器号
driver%~pn
:仅将 %n 扩充到一个路径
path%~nn
:仅将 %n 扩充到一个文件名
name%~xn
:仅将 %n 扩充到一个文件扩展名
extension%~sn
:扩充的路径只含有短名
short%~an
:将 %n 扩充到文件的文件属性
attributes%~tn
:将 %n 扩充到文件的日期/时间
time%~zn
:将 %n 扩充到文件的大小
以上的结果是可以随意组合的。
echo 【%0】【%~d0】【%~p0】【%~n0】【%~x0】
:: 【test.bat】【D:】【atch】【test】【.bat】
echo 【%~a0】【%~t0】【%~z0】
:: 【--a--------】【2020/06/15 00:07】【256】
echo 【%~dp0】【%~dpnx0】【%~f0】【%~s0】
:: 【D:atch】【D:atch est.bat】【D:atch est.bat】【D:atch est.bat】
重定向
有三个通用的标准文件
(也称为标准流
):
- 标准输入文件(
stdin
)包含程序/脚本的输入,使用数字0
进行引用 - 标准输出文件(
stdout
)被用来写输出以显示在屏幕上,使用数字1
进行引用 - 标准错误文件(
stderr
)包含用于显示在屏幕上的任何错误消息,使用数字2
进行引用
输出重定向
>
:传递并且覆盖
,他的作用是将运行的结果
传递到后面的文件
或默认的系统控制台
>>
:传递并在文件的末尾追加
,而不是覆盖
基本用法
批处理文件中的一种常见做法是将程序的输出发送到日志文件
echo 【hello】>test.txt
echo 【hello 】>test.txt
echo 【world】>>test.txt
tree > list.txt
dir . >> list.txt
再看 echo 语句
echo hello
完整的语句应该是echo hello 1>con 2>con
,意思是将 echo 命令的结果中的标准输出和标准错误
输出输出到控制台con
中。
echo hello 1>con
echo hello >con %重定向符号>默认是1,所以可以省略1%
echo hello >con 2>con
一些特殊用法
echo hello >NUL %伪文件【NUL】用于丢弃程序的任何输出%
TYPE CON >input.txt
:: 将用户所有输入内容都保存到一个EOF字符中, 稍后它将所有输入重定向到指定文件中
输入重定向
- 将其
后面的文件的内容
作为其前面命令的输入
- 即
从文件中读入命令输入
,而不是从键盘(标准输入)中读入
set /p a=<test.txt
echo 读取文件第一行内容,并赋值给变量:%a%
CLIP <test.txt
:: 读取文件内容,并复制到粘贴板中
>& 和 <&
>&
:将一个句柄
的输出写入到另一个句柄
的输入中<&
:刚好和>&
相反,从一个句柄
读取输入并将其写入到另一个句柄
输出中
>1 与 >&1 的区别
2>1
表示将标准错误重定向到文件1
,其中的1代表文件1,而不代表标准输出2>&1
表示将标准错误重定向到标准输出
&1
才代表标准输出
ls 2>1 %执行后会输出一个空的文件1%
ls 1>2 %执行后会将ls命令的结果输出到文件2中%
ls not_exit_file 2>3 %执行后因为指定文件不存在导致的的错误信息重定向到了文件3中%
ls 2>&1 %将标准错误重定向到标准输出,不会生成1这个文件%
ls 1>1 2>&1 %将标准输出重定向到文件1,同时将标准错误重定向到标准输出%
ls not_exit_file 1>1 2>&1 %执行后因为指定文件不存在导致的的错误信息重定向到了文件1中%
ls not_exit_file >1 2>&1 %重定向符号>默认是1,所以可以省略1%
> 和 >& 的顺序
test.bat >log.txt 2>&1
:: 先把标准输出重定向到 log.txt 中,再把标准错误重定向到标准输出
:: 因为标准输出已经重定向到 log.txt 中了,所以标准错误也会重定向到了 log.txt 中
test.bat 2>&1 >log.txt
:: 先把标准错误重定向到标准输出,但此时标准输出还是在终端,所以重定向后标准错误仍然保持在终端
:: 然后把标准输出重定向到 log.txt 中,但是标准错误仍然保持在终端
重定向脚本日志
test.bat > log.txt
:: 把脚本执行结果(stdout)输出到 log.txt 中,错误信息(stderr)依旧打印在控制台
test.bat > log.txt 2>&1
:: 把脚本执行结果(stdout)和错误信息(stderr)都输出到 log.txt 中
test.bat > log.txt 2>error.txt
:: 把脚本执行结果(stdout)输出到 log.txt 中,同时把错误信息(stderr)输出到 error.txt 中
管道命令符
管道符|
的作用是,将符号前的进程输出
当做符号后进程的输入
,或者说,将前面命令的结果
作为后面条命令的参数
来使用。
管道命令能够将一个命令的执行结果经过筛选
,只保留我们需要的信息。
dir . | find "txt" %查找当前文目录中含有txt的所有目录及文件%
cat test.txt | grep bqt %打印指定文件中,所有包含bqt的那一行的内容%
echo %date% | clip %复制指定内容到剪贴板中%
组合、管道、重定向命令的优先级
管道命令
> 重定向命令
> 组合命令
dir c: && dir d: > 1.txt
:: 执行后1.txt里只有D盘的信息,因为组合命令&&没有重定向命令>的优先级高
dir . | find "txt" && echo 包 && echo 青天>1.txt
:: 执行顺序为【dir . | find "txt"】【echo 包】【echo 青天>1.txt】,执行后文件内容为:青天
2019-08-12