BAT 批处理 常用功能 工具 函数 补充 [MD]

博文地址

我的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 reaching goto :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缩写,即为路径、目录
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

原文地址:https://www.cnblogs.com/baiqiantao/p/11337426.html