Windows批处理脚本编写学习


=Start=

缘由:

前段时间因为工作需要简单学习了一下Windows上batch脚本的编写,已经可以用batch脚本实现一些简单的常用功能,这里简要记录一下,方便以后有需要的时候进行参考。

正文:

参考解答:

起因在于我有一个Windows软件下发安装的需求,但现在软件下发通道那里做的还比较糙,没办法进行一些细粒度的判断和控制,要安装的软件本身也不是特别“智能”,这时我就需要自己写一个batch脚本来实现判断是否安装、比较安装版本、下载安装文件、上报安装结果和状态的功能。下面就简单记录一下在实现这个功能时的拆解和搜索过程,方便后面参考。

简单来看常规操作就是以下几点:

  • 要知道获取相关信息的命令是什么(比如获取IP用ipconfig命令)
  • 管道/重定向
  • 文件操作(创建/打印/复制/删除/压缩/解压/……)
  • 字符串查找/截取/比较/拼接/切分/……
  • 网络请求
Windows 命令行/batch脚本中如何获取主机系统相关信息?

IP/MAC地址
主机名
操作系统版本
序列号

如果仅仅只是在命令行上面看的话都还比较简单直接:

ipconfig /all
hostname
wmic os get caption
wmic bios get serialnumber

不过如果想把具体的值通过接口进行上报的话就需要进行字符串提取和格式化,Windows上原生的命令/batch脚本处理能力相对Linux要弱很多(主要是Windows的我不熟,PowerShell也不会而且貌似也存在版本差异?),处理起来就麻烦了不少。

比如:for命令的功能有限且限制较多,没办法在 command 那里使用管道操作符,只能先将复合命令的结果重定向到文件里面,然后处理文件内容,这里就涉及到字符串处理了——字符串查找/提取/拼接……Linux上几行命令就能完成的功能在Windows上用batch来实现就需要一段代码,而且还不优美。

for循环中使用变量时的注意事项

# 注意下面2个for循环的不同之处
# 一个有 /f 选项,所有后面的括号里面有双引号
# 一个没有 /f 选项,后面没有 tokens 参数以及括号里面也没有双引号
for /f "tokens=1" %%a in ("%date:/=-%") do (set mydate=%%a)
for %%a in (%time::=%) do (set mytime=%%a)

# batch脚本中 %~dp0 和 %~n0 变量的取值
set tmpfile="%~dp0%~n0-%mydate%.txt"


# batch脚本中for循环使用 call 子例程的方式来更新变量的值(直接用的话值是固定的)
:: set variable ip
set ip=
ipconfig | findstr /i ipv | findstr 1[97]2 >%tmpfile%
for /f "tokens=2 delims=:" %%a in (%tmpfile%) do (
echo %%a
call :subroutine_ip %%a
)
:subroutine_ip
set ip=%1,%ip%
goto :eof

set ip=%ip:~0,-1%
echo %ip%
Windows上如何判断操作系统是32位的还是64位的?
# 操作系统的架构
wmic os get osarchitecture

# 处理器的架构
echo %PROCESSOR_ARCHITECTURE%
batch批处理脚本中如何判断某个变量是否为空值?
IF [%1] == [] GOTO MyLabel
:: or
IF "%~1" == "" GOTO MyLabel
batch批处理脚本中如何判断字符串是否不相等?
if NOT "asdf" == "fdas" echo asdf
batch批处理脚本中如何进行字符串截取?
语法:
%variable:~start_index%
%variable:~start_index,end_index%

:: 截取ip变量子串,去掉最后一个字符
set ip=%ip:~0,-1%
bat批处理中的注释语法
:: comments here
Rem comments here
bat批处理中如何做字符串替换
@echo off 
set str=This message needs changed. 
echo %str% 

set str=%str:needs=has% 
echo %str%
batch批处理脚本中如何获取当前的日期时间?
for /f "tokens=1" %%a in ("%date:/=-%") do (set mydate=%%a)

for %%a in (%time::=%) do (set mytime=%%a)
Windows下如何进行文件下载和HTTP请求操作
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://ixyzero.com/blog/awk_sed.txt', 'awk_sed.txt')"

powershell -Command "Invoke-WebRequest https://ixyzero.com/blog/awk_sed.txt -OutFile awk_sed.txt"

curl -o awk_sed.txt https://ixyzero.com/blog/awk_sed.txt
Windows的命令行下的文件操作
# 创建空文件
type nul > filename.txt
copy NUL EMptyFile.txt
copy /b NUL EmptyFile.txt
echo. 2>EmptyFile.txt
REM. > empty.file
fsutil file createnew file.cmd 0 # to create a file on a mapped drive

# 创建指定大小的文件
fsutil file createnew filename.txt 1000

# 打印文件内容,类似于Linux上的cat命令
type filename.txt

# 删除文件,类似于Linux上的rm命令
del filename.txt

# 查看当前目录下有哪些文件,类似于Linux上的ls命令
dir

# 创建目录
mkdir dir_name

# 删除目录
rmdir dir_name
Windows的命令行下的复制
# 无任何选项,仅复制文件,不复制目录
xcopy \path\to\source \path\to\dest

# 无任何选项,目标是一个还没创建的目录,需要交互式互动才可继续
xcopy \path\to\source \path\to\dest\none_exist_dir

# 借助管道将上面的命令从交互式改成静默执行的
echo d | xcopy \path\to\source \path\to\dest\none_exist_dir

# 添加 /e 选项,复制包括空目录在内的目录和子目录,但是如果有同名文件,则会需要交互以确定是否进行覆盖
xcopy /e \path\to\source \path\to\dest

# 添加 /e 和 /y 选项,直接复制包括空目录在内的目录和子目录,如果有同名文件,直接进行覆盖即可
xcopy /e /y \path\to\source \path\to\dest

# 简而言之,一个简单实用的xcopy命令就是——直接将源目录拷贝到一个之前不存在的目录下
echo d | xcopy /y /e \path\to\source \path\to\dest\none_exist_dir

xcopy /?
...
  /S           复制目录和子目录,不包括空目录。
[*]  /E           复制目录和子目录,包括空目录。与 /S /E 相同。可以用来修改 /T。
[*]  /C           即使有错误,也继续复制。
[*]  /I           如果目标不存在,且要复制多个文件,则假定目标必须是目录。
  /Q           复制时不显示文件名。
  /F           复制时显示完整的源文件名和目标文件名。
  /L           显示要复制的文件。
  /G           允许将加密文件复制到不支持加密的目标。
[*]  /H           隐藏文件和系统文件也会复制。
  /R           覆盖只读文件。
  /T           创建目录结构,但不复制文件。不包括空目录或子目录。/T /E 包括空目录和子目录。
  /U           只复制已经存在于目标中的文件。
  /K           复制属性。一般的 Xcopy 会重置只读属性。
  /N           用生成的短名称复制。
  /O           复制文件所有权和 ACL 信息。
  /X           复制文件审核设置(隐含 /O)。
[*]  /Y           取消提示以确认要覆盖现有目标文件。
  /-Y          触发提示,以确认要覆盖现有目标文件。
  /Z           在可重新启动模式下复制网络文件。
  /B           复制符号链接本身与链接目标。
  /J           复制时不使用缓冲的 I/O。推荐复制大文件时使用。
  /COMPRESS    如果适用,在传输期间请求网络压缩。
...
参考链接:

for循环中使用变量时的注意事项
https://ss64.com/nt/for.html

Windows上如何判断操作系统是32位的还是64位的?
https://superuser.com/questions/321988/how-do-i-determine-if-my-windows-is-32-bit-or-64-bit-using-a-command

batch批处理脚本中如何判断某个变量是否为空值?
https://stackoverflow.com/questions/2541767/what-is-the-proper-way-to-test-if-a-parameter-is-empty-in-a-batch-file

batch批处理脚本中如何判断字符串是否不相等?
https://stackoverflow.com/questions/1421441/batch-not-equal-inequality-operator
https://ss64.com/nt/if.html

batch批处理脚本中如何进行字符串截取?
https://stackoverflow.com/questions/636381/what-is-the-best-way-to-do-a-substring-in-a-batch-file
https://ss64.com/nt/syntax-substring.html

Batch Script – Comments
https://www.tutorialspoint.com/batch_script/batch_script_comments.htm

How to “comment-out” (add comment) in a batch/cmd?
https://stackoverflow.com/questions/11269338/how-to-comment-out-add-comment-in-a-batch-cmd

Batch Script – Replace a String
https://www.tutorialspoint.com/batch_script/batch_script_replace_string.htm

How to replace substrings in windows batch file
https://stackoverflow.com/questions/5273937/how-to-replace-substrings-in-windows-batch-file/5274061#5274061

batch批处理脚本中如何获取当前的日期时间?
https://stackoverflow.com/questions/203090/how-do-i-get-current-date-time-on-the-windows-command-line-in-a-suitable-format

CURL was added to Windows 10 (1903) from build 17063 or later.
https://ss64.com/nt/curl.html

Windows batch file file download from a URL
https://stackoverflow.com/questions/4619088/windows-batch-file-file-download-from-a-url

Windows的命令行下的文件操作
https://stackoverflow.com/questions/1702762/how-can-i-create-an-empty-file-at-the-command-line-in-windows

Windows的命令行下的复制
https://ss64.com/nt/xcopy.html

=END=


《“Windows批处理脚本编写学习”》 有 3 条评论

  1. 如何从命令行获取Windows的系统版本号?
    How to get the ACTUAL version number for Windows 10 from command line? (NOT build number!)
    https://superuser.com/questions/1519110/how-to-get-the-actual-version-number-for-windows-10-from-command-line-not-buil
    `
    >Reg Query “HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion” | findstr ReleaseId

    >powershell -Command “(Get-ItemProperty -Path ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion’).ReleaseId”

    >powershell -Command “Get-ComputerInfo -Property WindowsVersion”

    >winver

    >wmic os get /?

    >wmic os get version /value
    Version=10.0.19041

    >wmic os get buildnumber /value
    BuildNumber=19041
    `

  2. 软件下发任务
    `
    1. 获取主机相关信息
    2. 判断X软件是否正在运行(根据运行中进程或是特定路径的文件)
    3. 若正在运行,再判断安装运行的版本,若版本太低就下载升级安装,若版本已是最新则只进行 curl 请求上报主机相关信息用于标记和记录,然后退出
    4. 若没有运行,则下载并执行安装包,然后等一会发送 curl 请求用于记录下载安装情况,再退出

    host/ip/sn/os/agent_proc_list

    涉及到的命令主要就是:
    hostname/ipconfig/wmic/tasklist/findstr/dir/start/curl/powershell/…
    `

  3. windows 技巧篇-查看文件夹被那个进程占用,文件夹占用解除方法
    https://cloud.tencent.com/developer/article/1703311
    `
    有时候我们关闭程序后,发现之前被程序占用的文件夹还是被占用状态。因为一些程序逻辑不完善的原因,常规的关闭并没有彻底的杀死进程。下面给大家介绍下查看占用文件夹进程的方法。

    第一步: 在【任务管理器】的【性能】tab页下面打开【资源监视器】。
    第二步: 在 cpu 页签里的【关联的句柄】处搜索被占用的文件夹路径。然后就能查到占用该文件夹相关的进程,右键结束就 ok 了。
    `

    windows查看占用文件的进程
    https://blog.csdn.net/qq_44098268/article/details/125153189

    windows 查看文件被哪个进程占用
    https://zhuanlan.zhihu.com/p/158119424
    `
    经常当我们删除文件时,有时会提示【操作无法完成,因为文件已在另一个程序中打开,请关闭该文件并重试】,到底是哪些程序呢?

    有时候一个一个找真不是办法,已经被这个问题折磨很久了,今天下决心要把它解决,找到办法了。如果系统是win10/win7,可以这么做:

    在开始菜单中的搜索框内输入“资源监视器”,回车,打开“资源监视器”。

    看下图,在“资源监视器”界面中,点击第二个选项卡“CPU”。在“关联的句柄”右侧搜索框内输入文件名称,点击右侧下拉箭头,就可以查看该文件被那几个程序占用了。

    选中程序,右击选择结束进程。

    现在就可以删除文件了。结束系统进程前最好查一下,看看能不能结束,免得出现问题,那就得不偿失了。
    `

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注