首页 > 技术文章 > bat基本操作

wesson2019-blog 2020-03-13 15:28 原文

bat操作


::采用ANSI编码或UTF-8强制设置
@echo off
chcp 65001

set dd=%date%
set tt=%time%
::取星期:
echo %dd:~10,6%
set tt1=%dd:~0,4%%dd:~5,2%%dd:~8,2%-%tt:~0,2%%tt:~3,2%%tt:~6,2%%tt:~9,2%
::时间格式20091710
set hour=%time:~,2%
if "%time:~,1%"==" " set hour=0%time:~1,1%
set anotherVariable=%date:~5,2%%date:~8,2%%date:~11,2%%hour%
::空格替换为0
set "tt1=%tt1: =0%"
copy e:\\bigFile.txt e:\\copyfile%tt1%.txt 
copy e:\\bigFile.txt d:\\copyfile.txt
::强制 所有子目录 不确认删除文件
del /f /s /q e:\copyfile%tt1%.txt
del /f /s /q d:\copyfile.txt
::删除文件夹
if exist D:\EFI\Temp( rd /s /q D:\EFI\Temp)

echo 生成时间戳验证码
call TimeStampVerificationCode.bat

::目录相关
echo 当前盘符:                    %~d0
echo 当前目录:                    %~dp0
set batdir=%~dp0
echo 当前盘符和路径的短文件名格式: %~sdp0
echo 当前批处理文件绝对路径:       %~f0
echo 当前CMD默认目录:             %cd%
::上一级目录路径
echo 当前目录:                    %cd%
cd..
echo 上一级目录路径是:            %cd%
::上一级目录名称这个有的地方好用有的会返回上级目录路径
echo 当前目录:                    %cd%
if %cd%==%cd:~,3% echo 当前目录已经是%cd:~,1%盘的根目录!&goto end
cd..
set "bd=%cd%"
cd..
set "bbd=%cd%"
if "%bbd%"=="%bd%" (echo 上一级目录是: %cd:~,1%盘的根目录!
) else call echo 上一级目录是: "%%bd:%bbd%\=%%"
:end
::当前盘符
echo 当前盘符: %cd:~,1%
::根目录
echo 根目录:   %cd:~,3%


::常用系统路径变量
echo 当前启动的系统的所在分区:  %SYSTEMDRIVE%
echo 当前启动的系统的所在目录:  %WINDIR%
echo 当前用户TEMP缓存变量:      %TEMP%
echo 当前用户数据变量:          %USERPROFILE% 
echo 当前用户环境变量:          %HOMEPATH%
echo 程序安装目录:              %PROGRAMFILES%
echo 默认应用程序存储数据的位置:%APPDATA% 
echo 启动当前的Cmd.exe的命令行: %CMDCMDLINE% 
echo 操作系统的名称:            %OS% 
echo 可执行的文件扩展名的列表:  %PATHEXT%

::循环
for /l %%i in (1 1 3) do (
echo %%i
call %batdir%TimeStampVerificationCode.bat
ping -n 2 127.0.0.1>nul
)


pause

echo 时间间隔(100ms级别)

set time_begin=%time%
set /A time_begin_minute=%time_begin:~3,2%
set /A time_begin_second=%time_begin:~-5,2%
set /A time_begin_millisec=%time_begin:~-2,2%
::其他脚本
set time_end=%time%
set /A time_end_minute=%time_end:~3,2%
set /A time_end_second=%time_end:~-5,2%
set /A time_end_millisec=%time_end:~-2,2%
if %time_end_millisec% lss %time_begin_millisec% set /A time_end_millisec+=100&set /A time_end_second-=1
if %time_end_second%   lss %time_begin_second%   set /A time_end_second+=60&set    /A time_end_minute-=1
set /A minute=time_end_minute-time_begin_minute
set /A second=time_end_second-time_begin_second
set /A millisec=time_end_millisec-time_begin_millisec
echo 运行结束!.........(%time_begin%-%time_end%)耗时:!minute!分!second!秒!millisec!0毫秒

bat传递参数

@echo off   
::%~1 第一个参数,除去双引号
echo %~0
echo arg1:%~1
echo arg2:%~2

pause

整行替换

::关闭显示并启用变量延迟,启用本地变量
@echo off&setlocal EnableDelayedExpansion
chcp 65001
set rootPath=E:\Src
echo.

set srcFile=%rootPath%\***.xml
set anotherVariable=logo.ico
echo !srcFile!更新图标:!anotherVariable! 
(for /F "delims=" %%a in (%srcFile%) do (
   set "line=%%a"  
   set "newLine=!line:ApplicationIcon>=!"
   if "!newLine!" neq "!line!" (
      set "newLine=    <ApplicationIcon>%anotherVariable%</ApplicationIcon>"
   ) 
   echo !newLine!
)) > 111.tmp
move /y 111.tmp !srcFile!

setlocal DisableDelayedExpansion
pause

指定字符串替换

::关闭显示并启用变量延迟,启用本地变量
@echo off&setlocal EnableDelayedExpansion
chcp 65001
set rootPath=E:\Src
echo.

set srcFile=%rootPath%\App.config
echo App.config更新信息:add key="Servers" value="10.100.10.85,www.baidu.com,www.cnblogs.com"
sed -i 's/add key=\x22Servers\x22 value=\x22www.baidu.com,10.100.10.85,www.cnblogs.com\x22/add key=\x22Servers\x22 value=\x2210.100.10.85,www.baidu.com,www.cnblogs.com\x22/g' !srcFile!
sed -i 's/add key=\x22Servers\x22 value=\x22www.baidu.com,www.cnblogs.com,10.100.10.85\x22/add key=\x22Servers\x22 value=\x2210.100.10.85,www.baidu.com,www.cnblogs.com\x22/g' !srcFile!

setlocal DisableDelayedExpansion
pause

使用 sed.exe,依赖 msys-2.0.dll

FOR语句

依次处理每个元素,直到所有的元素都被处理为止。一般规则如下:

for /f "eol=; skip=3 delims=, tokens=1,* usebackq" %%i in (command1) do command2

/f eol skip delims tokens usebackq
以行为单位处理文本文 忽略以指定字符打头的行 跳过无用的行 切分字符串 定点提取 增强型参数
一般语句 含参usebackq
for /f %%i in (文件名) do () for /f "usebackq" %%i in ("文件名") do ()
for /f %%i in ('命令语句') do () for /f "usebackq" %%i in (`命令语句`) do ()
for /f %%i in ("字符串") do () for /f "usebackq" %%i in ('字符串') do ()

变量延迟

批处理的执行过程是“自上而下,逐条执行”。“逐条”并不等同于“逐行”。这个“条”,是“一条完整的语句”的意思,并不是指“一行代码”。什么样的语句才算“一条完整的语句”呢?

  • 复合语句,整个复合语句是一条完整的语句,常见的复合语句有:for,if else,用连接符&、||和&&连接的语句,用管道符号|连接的语句,用括号括起来的,由多条语句组合而成的语句块。
  • 非复合语句,如果该语句占据了一行的位置,则该行代码为一条完整的语句。

预处理机制,在代码“逐条”执行的过程中,cmd.exe 这个批处理解释器会对每条语句做一些预处理工作:
首先,把一条完整的语句读入内存中(不管这条语句有多少行,它们都会被一起读入),然后,识别出哪些部分是命令关键字,哪些是开关、哪些是参数,哪些是变量引用......
如果代码语法有误,则给出错误提示或退出批处理环境;如果顺利通过,接下来,就把该条语句中所有被引用的变量及变量两边的百分号对,用这条语句被读入内存之前就已经赋予该变量的具体值来替换......
当所有的预处理工作完成之后,批处理才会执行每条完整语句内部每个命令的原有功能。也就是说,如果命令语句中含有变量引用(变量及紧邻它左右的百分号对),并且某个变量的值在命令的执行过程中被改变了,即使该条语句内部的其他地方也用到了这个变量,也不会用最新的值去替换它们,因为某条语句在被预处理的时候,所有的变量引用都已经被替换成字符串常量了,变量值在复合语句内部被改变,不会影响到语句内部的其他任何地方。

预处理使用了变量扩展,用具体的值去替换被引用的变量及紧贴在它左右的那对百分号。我们可以使用变量延迟扩展语句,让变量的扩展行为延迟一下,使复合语句内部的变量实时感知到变量值的变化。

经常采用的方法是在适当位置使用 setlocal enabledelayedexpansion,该语句让变量成为局部变量,并延迟它的扩展行为;此时复合语句的语法有所变化:

复合语句 变量延迟
%num% !num!

for /r 与 dir /ad /s

列举目录 优点 缺点
for /r 只通过 1 条语句就可以同时实现获取目录路径和处理目录路径的操作;遍历文件夹的时候,是边列举边处理的,获取到一条路径就处理一条路径,内存占用小,处理大量路径的时候不会产生停顿感; 不能获取到带隐藏属性的目录,会产生遗漏;不能获取带指定属性的目录;
dir /ad /s 能一次性获取带任意属性的目录,不会产生遗漏; 能通过指定不同的参数获取带任意属性的目录,更具灵活性; 仅能获取到目录路径;for /f 语句之后,需要先列举完所有的路径放入内存之后,才能对每一条路径进行进一步的处理,处理大量路径时,内存占用量偏大,并且在前期会产生明显的停顿感,用户体验度不够好;
  • 若仅仅是为了获取某文件夹及其所有子文件夹的路径的话,可使用 dir /ad /b /s 语句;
  • 若需要过滤带隐藏属性的文件夹的话,for /r 和 dir 语句都可以实现,但 for /r 内存占用小,处理速度快;
  • 若需要获取所有文件夹,则除了 dir /ad /b /s 外,别无选择,因为 for /r语句会遗漏带隐藏属性的文件夹;

for /d

匹配第一层目录。它仅能匹配当前目录下的第一级文件夹,或是指定位置上的文件夹,而不能匹配更深层次的子文件夹。

for /l

for /l %%i in (x,y,z) do (......)
计数循环。当循环次数确定的时候,选择此语句。当循环次数不确定的时候,用 goto 语句,要用 if 之类的条件语句来判断何时结束 goto 跳转。

统计脚本耗时

set time_begin=%time%
set /A time_begin_minute=%time_begin:~3,2%
set /A time_begin_second=%time_begin:~-5,2%
set /A time_begin_millisec=%time_begin:~-2,2%
::其他脚本
set time_end=%time%
set /A time_end_minute=%time_end:~3,2%
set /A time_end_second=%time_end:~-5,2%
set /A time_end_millisec=%time_end:~-2,2%
if %time_end_millisec% lss %time_begin_millisec% set /A time_end_millisec+=100&set /A time_end_second-=1
if %time_end_second%   lss %time_begin_second%   set /A time_end_second+=60&set    /A time_end_minute-=1
set /A minute=time_end_minute-time_begin_minute
set /A second=time_end_second-time_begin_second
set /A millisec=time_end_millisec-time_begin_millisec
echo 执行成功!.........(%time_begin%-%time_end%)耗时:!minute!分!second!秒!millisec!0毫秒

bat获取exe输出值


cd /d **\Debug
BatHelper.exe CreateVersionInfo>result.txt
set result=0
:: 读取首行数据
for /f "delims=" %%i in (result.txt) do (
   set /a revision=%%i& goto _ExitForLoop
)
:_ExitForLoop
del result.txt
echo !result!
cd "%~dp0"

namespace BatHelper.Program
static void Main(string[] args)
{
    if (args.Length > 0)
    {
        string methodName = args[0];
        InvokeStaticMethod(typeof(Program), methodName, args.Skip(1).ToArray());
    }
}
// 创建版本信息(形如:35509)
static void CreateVersionInfo()
{
    var dt = DateTime.Now;
    var rslt = $"{dt.DayOfYear}{dt:HH}";
    Console.WriteLine(rslt);
}

InvokeStaticMethod

打开目录

%SystemRoot%\explorer.exe  "%dir%"\bin

推荐阅读