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


    博文地址 
    markdown版本地址

    我的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

  • 相关阅读:
    C++ 数字、string 简便互转
    【C语言】递归函数DigitSum(n)
    UVALIVE 4287 Proving Equivalences (强连通分量+缩点)
    【linux驱动分析】misc设备驱动
    C++ auto 与 register、static keyword 浅析
    spring 计时器
    Spring注解配置定时任务<task:annotation-driven/>
    去除ckeditor上传图片预览中的英文字母
    编码规范
    git 手动操作
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/6527100.html
Copyright © 2020-2023  润新知