27. Windows批处理与Linux Shell脚本编写指南

1.前言

前面的几个章节我们简单学习了一下如何使用Linux系统,以及如何用VS来开发Linux程序。

一般来说,对于Linux的基础使用也就这样了:基本命令、开发程序。

想要更加深入的学习Linux,就还得学习各种常用软件的使用方法,以及更多命令。

而本章介绍的脚本,无论是在Windos系统,还是Linux系统上,都相当重要。

没错,C/C++程序员学的东西就是非常杂,基本什么都得会点。

一般在Linxu系统上使用脚本频率更高。

当然,各个系统之间的脚本编写方法是不同的,除非你使用一个中间层,比如python语言,来抹平不同平台脚本的差异性,否则就得分别学习不同平台脚本的编写方式。

虽说是要学不同平台的脚本编写,看似有点多,但事实上脚本之间都有互通性,只是脚本的语法略有差异。

所以本章就来分别详细介绍这两种平台的脚本编写方式。

2.什么是脚本?

为了更加清晰地理解什么是脚本,最直观的方法就是看一看别人写的专业脚本到底长啥样。

大家应该都是装了VS的,所以我们就可以来到VS的一个用于搭建构造环境的脚本:

D:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build

根据大家安装的版本,位置,上面这个目录可能略有不同,可以自己调整,然后就可以看到下方的几个脚本文件:

在这里插入图片描述

没错,在Windows系统中以.bat后缀结尾的文件,就是一个脚本文件(在Windows系统中,称其为批处理),双击它们,就可以像双击一个exe程序一样,可以直接运行。

这里我们来看一看这个占用内存最大的脚本文件vcvarsall.bat

在这里插入图片描述

不要直接点它,那是直接运行了,右键它,然后点击编辑:

在这里插入图片描述

然后我们就可以看到上面这些看起来很奇怪的字符串。

通过这里我们可以得出什么结论吗?

这说明脚本文件是不依赖于任何编译器的,我们可以直接在记事本里面写脚本,只要将其保存为.bat后缀,就能直接点击运行!

是不是突然就理解那些用记事本编程的人了?看起来特别厉害的样子,也许就是一个脚本小子。

当然也不是贬低的意思,毕竟我们写出来的软件就是用来用的,能把软件用好也是一个技能。

这并不困难(至少与学习C/C++相比而言),所以我这里只使用了一章的篇幅来大致介绍两个平台的脚本开发流程

这里只介绍基础知识,想要更加深入的学习,就还得自行学习各种命令的高阶用法。

3.Windows脚本

首先我们直接来看Windows脚本的编写流程,毕竟绝大部分人应该都习惯于使用Windows。

注意:在脚本语言中,习惯于一行写一句命令,且命令前无空格

技巧:windows命令的参数是通过/传递的,如果不清楚一个命令如何用,就可以传入/?,以获取命令的详细解释

3.1 如何写脚本

那么我们应该如何写脚本呢?很简单,如前面所说,记事本即可

新建一个记事本,任意命名,但后缀需要更改为.bat:

image-20231012162749413

然后用记事本打开并编辑它。

如果你有其它编辑软件,甚至用VS打开它进行编辑,都是可以的。

然后输入一个pause,即暂停的意思:

image.png

保存后,双击这个文件:

image.png

看到没,这就相当于我们自己进入控制台,然后输入pause命令是一样的效果,而所谓脚本,就是将这些大量的命令放在一起,统一执行,以实现某些功能。

pause这个命令的作用就是暂停,因为脚本文件执行完成后,就直接退出了,如果没有暂停按钮,你可能就啥也没看到,脚本就已经执行完了。

当你按下任意键,就会继续执行pause命令之后的命令,如果后面没有命令了,就退出脚本文件

3.2 关闭回显

上面我们使用了一下pause命令,但执行后,它会显示路径,以及执行的这个命令名称。

但有时候,我们就不喜欢它显示出来,怎么办呢?

关闭回显有两种方法:

  • 关闭单个命令的回显

如果只想要关闭一条命令的回显,只需要在命令的最前面添加@符号即可:

@pause

执行后:

image.png

没有回显是不是就好看多了!

  • 关闭所有回显

上面那种方法只适用于关闭个别命令,想要关闭所有命令,就得在所有命令前面都添加@,那未免就有点太麻烦了.

所以就有了直接一次性关闭所有命令回显的方法:

@echo off
pause

echo这个命令就是用来显示字符串的,其后带上参数off,就可以关闭当前脚本所有命令的自动回显。

然后再在这个命令前面添加@,表示将这个echo off命令本身的回显也关闭掉,这样就实现了整个脚本文件都处于无回显的状态了。

因为这里只有一个命令,所以看起来效果与前面相同,你可以在后面多添加几条命令,就会发现所有命令都没有回显,只会显示命令的执行结果。

3.3 注释

脚本语言同样也是有注释的,毕竟谁能在几个月乃至几年后还能记住当初自己写的是个什么玩意呢?

批处理脚本(windows平台下脚本的一般叫法)的注释方式有两种:

  1. 第一种是:REM 后跟注释(小写也可,其后要与注释有空格)
  2. 第二种是:: 后跟注释

比如上面的:

在这里插入图片描述

这两个其后跟着的就是命令注释。

注意rem本身也是一个命令,所以也会有回显,因此VS在前面添加了@,以关闭回显,而:不是命令,没有回显,不需要关闭回显。

3.4 输出(echo)

作为脚本语言,输出肯定是不可或缺的。

而批处理文件中的输出命令就是echo,前面我们也提到过,它还可以关闭回显。

其使用方法很简单,就是将你想要显示出来的内容跟在这个命令之后就行了:

@echo off
echo hahahhahahhahha
pause

但你想要输出中文的时候,却可能会发现输出的是乱码。

乱码的根本原因是啥?就是保存的编码格式与读取的编码格式不同!电脑一般为ANSI编码,而目前记事本默认使用的utf-8编码。

更多原理,可以参考本站的这篇文章:编码

所以只需要将文件另存为ansi编码即可:

image.png

在记事本中,可以按快捷键Ctrl+Shift+S弹出“另存为”窗口,然后就可以选择编码了。

3.5 变量(set)

既然脚本被称为语言,那就肯定会有变量,但脚本语言中的变量与我们平时在C/C++中所使用的有点不一样。

批处理中的变量都是通过set命令来指定的:

@echo off
set msg=www.kucoding.com
echo %msg%
pause

只需要通过=赋值即可,同时要注意=前后不要有空格,否则会出错。

而输出就用前面提到的echo命令,注意变量的使用要用两个%包起来,不然echo命令无法识别这是一个变量,而将它直接当做一个字符串处理的。

但这样只能赋值字符串,我们有时候想要计算,需要保存数字怎么办呢?

还是set命令,使用/a参数即可:(注意windows命令参数通过 /,而linux参数通过-表示)

@echo off
set /a a=10
set /a b=20
set /a c=%a%+%b%
echo %c%
pause

上面设置了两个变量,然后相加,最后输出相加结果:

image.png

当然乘除也是可以的,但注意除的精确度并不高,使用的也较少。

除了上面这种自己设置变量,自己使用外,我们有时候可能还需要接受用户输入的参数:

比如C/C++中的main函数,可以接受用户输入的参数。

事实上批处理中同样可以,通过%后面紧跟数字,即可表示用户输入的第几个参数,比如:

@echo off
echo %1
echo %2
echo %3
pause

上面的命令就是直接输出用户输入的前三个参数:

image.png

然后我先自己启动一个控制台,再执行这个文件,其后跟着参数即可,就能正常输出了!

还有另一种需求,那就是我们需要获取用户的输入, 通过指定/p参数即可:

@echo off
set /p a=请输入a值:
set /p b=请输入b值:
set /a c=%a%+%b%
echo %c%
pause

当添加了/p参数,=符号之后的内容就是提示语了,用起来也还是很简单。

效果如下:

image.png

更多关于set命令的使用方法,可以在控制台中输入set /?获取。

3.6 判断(if)

除了使用变量外,判断语句也很常见。

使用方法就是 if 判断语句 (为真执行的内容) else (为假执行的内容)

比如下面:

@echo off
set a=abcd
set b=acbd
if %a%==%b% (echo a与b相等) else (echo a与b不相等)
pause

注意,只有==这个符号可以被使用,其用处就是判断两个字符串是否相等,诸如>,<这些符号是没有用的,会出错。

如果你想要使用其它判断操作,需要用到下面的操作符:

操作 功能
equ 等于
neq 不等于
lss 小于
leq 小于等于
gtr 大于
geq 大于等于

比如上面的==就可以改写为:

if %a% equ %b% (echo a与b相等) else (echo a与b不相等)

注意其后要执行的命令,最好都加上()

当然,如果你觉得上面这样写不好看,可以改写为:

if %a% equ %b% (
echo a与b相等
) else (
echo a与b不相等
)

这样就可以在判断完成后的执行语句中,多写几行命令

注意:因为else关键字必须在if这行命令的最后,所以想要分行写,那个(必须写在if这一行的最后,意味着if语句并未结束、还需要继续读取下一行的内容,不能将(也另起一行,否则就会出错。

下面这样写就是的:

if %a% equ %b%