Angular 2 工具箱的 Shell 脚本





5.00/5 (1投票)
本文介绍了我用于进一步自动化 Angular 2 应用程序开发的一些强大 shell 脚本。
引言
即使是最健壮、设计良好的开发环境,也几乎总能通过更多的自动化来改进。
当我跳过教程后,我很快就意识到,通过形式为 shell 脚本(Windows NT 命令脚本)的自动化,可以大大简化工作。
背景
在我漫长的开发生涯中,我一直致力于自动化许多重复的、容易出错的杂务,这些杂务会分散我处理手头任务的注意力,尤其是那些涉及必须按特定顺序完成的步骤的任务。起初,这种自动化 consisted of little IBM JCL (Job Control Language) decks that I kept in my personal code repository. 当我开始使用个人电脑时,那些 JCL deck 被批处理文件(现在有时称为 shell 脚本或 Windows NT Command Scripts)所取代。
在过去的大约 5 年里,为这些任务使用 PowerShell 已经变得很流行。尽管我非常擅长用 C# 编写程序,其中一些程序也被纳入了这个工具包,但 PowerShell 的学习曲线非常陡峭,而且不适合日常使用,除非你有现成的商业代码签名证书,并且愿意投入时间在所有脚本中使用它们。虽然存在变通方法,但一旦我能实现任何一种变通方法,我就可以写好、测试并投入生产我的 Windows NT 命令脚本了。
本文配套的包包含九个 shell 脚本和程序(32 位原生代码和托管代码的混合),我在 Angular 工作中使用它们,总结如下表。
FileName | 描述 |
---|---|
Date2FN.exe | 将 LastWriteTime 追加到文件名。 |
LSNEWEST.BAT | 返回与通配符匹配的最新的文件名。其他几个脚本调用此脚本。 |
MAKEZIP_DAG.CMD | 使用 WinZip 或 PK-Zip 来创建目录的备份存档。 |
SaveChromeDeveloperConsoleLog.CMD | 从快捷方式运行此脚本,该快捷方式将其工作目录设置为您要收集 Chrome 控制台日志的目录。保存日志时,将其命名为 localhost.log;此脚本使每个文件名唯一。 |
StartAngularApp.CMD | 从快捷方式运行此脚本,该快捷方式将其工作目录设置为您创建 Angular 2 应用程序并希望对其进行工作的目录。该脚本将查找从 seed 中提取的应用程序源文件。 |
StartAngularDevWebServer.CMD | CreateNewAngularApp.CMD 和 StartAngularApp.CMD 都使用此脚本来启动 Angular CLI 附带的 Web 服务器。由于我尚未完成测试,因此 CreateNewAngularApp.CMD 已省略。 |
WWPause.exe | 这个健壮的内部 PAUSE 命令的替代品,只响应回车符或 CTRL-C。 |
wwsleep.EXE | 此程序与 sleep.exe 类似,不同之处在于其内存占用量要小得多。 |
包中有两个基本相同的 Excel 文档。
ToolboxInventory_Compact.XLSX
包含一个工作表,该工作表配置为仅显示您实际运行的脚本和程序。ToolboxInventory.xlsx
包含一个工作表,列出了包中的所有内容,包括辅助 DLL。
两个工作簿实际上包含相同的信息,但 ToolboxInventory_Compact.XLSX
隐藏了除您实际使用的程序之外的所有内容。我将留给您自己去发现我是如何做到的。
使用代码
大多数 Windows NT 命令脚本旨在连接到桌面快捷方式,利用它们的“启动 in”(工作目录)属性来设置解析相对路径引用的默认目录。
Date2FN.exe
、 WWPause.exe
和 wwsleep.EXE
是通用的实用程序,可用于各种用途。我有许多其他脚本使用了这三个程序,而 Date2FN.exe
本身就是一个非常方便的命令行实用程序。
关注点
经典的批处理文件 LSNEWEST.BAT
相当直接。它最不寻常之处在于它通过环境变量 LSNEWEST
来接收输入和返回输出,并且它为两者使用了相同的变量。这主要是工程便利性的问题,因为环境变量是返回函数(子例程)结果的唯一可用设施。
dir "%LSNEWEST%" /b /od > %TEMP%\LSNEWEST.TMP
for /f %%i in (%TEMP%\LSNEWEST.TMP) do set LSNEWEST=%%i
del %TEMP%\LSNEWEST.TMP
- 环境变量
LSNEWEST
中的文件规范被输入到内部dir
命令,该命令被指示返回按修改日期从旧到新排序的纯文件名列表。 - 列表从 %TEMP%\LSNEWEST.TMP 读取,然后
LSNEWEST
被更新为文件名,这样当控制跳出循环时,它将包含最新的文件名。 - 文件列表已完成其任务,将被丢弃。
%TEMP% 环境变量包含用户临时(临时)目录的名称,该目录保证是可写的。
您可能会将 SaveChromeDeveloperConsoleLog.CMD
连接到桌面快捷方式。除了将 LSNEWEST.BAT
视为子例程外,它还会调用一个内部子例程 fnglob
,该子例程接受两个参数,如下所示。
call :fnglob LSNEWEST %SRCFN%
第一个参数是 LSNEWEST
,一个字符串文字,而 SRCFN
存储第一个(也是唯一的)参数的值(如果存在),或者 Chrome 控制台日志的默认名称 localhost.log
。当 fnglob
返回时,LSNEWEST
已被转换为同名的环境变量,其中包含 LSNEWEST.BAT
所需的 glob。
由于 SRCFN
在传递到子例程时会进行扩展,因此它会保留其正常的边界标记。
Date2FN.exe -r !SRCFN!
call LSNEWEST.BAT
start !LSNEWEST!
虽然未展开的字符串可以安全地传递到 fnglob
,但接下来的三个命令需要由感叹号标记强制延迟展开。
函数 fnglob
大体上是直接的。
:fnglob <pglob> <pfilename>
(
setlocal EnableDelayedExpansion
set fnpath=%~dpn2
set fnextn=%~x2
set "fnglob=!fnpath!*!fnextn!"
if "%_SaveChromeDeveloperConsoleLog%" equ "DEBUG" (
echo.
echo -------------------------
echo Within fnglob:
echo Arg 1 = %1
echo Arg 2 = %2
echo fnpath = !fnpath!
echo fnextn = !fnextn!
echo fnglob = !fnglob!
echo -------------------------
echo.
)
)
(
endlocal
if "%_SaveChromeDeveloperConsoleLog%" equ "DEBUG" (
echo.
echo -------------------------
echo Exiting fnglob:
echo -------------------------
echo.
echo fnglob = %fnglob%
)
set "%~1=%fnglob%"
exit /b
)
出现在函数名称旁边的两个字符串,<pglob> <pfilename>
,是参数,批处理文件将其视为注释。
受另一个延迟展开的 setlocal
块的保护,fnpath
和 fnextn
分别被设置为直到扩展名的输入文件规范和扩展名本身。下一个命令构造成为第三个环境变量 fnglob
值的字符串。
If
块内的代码,if "%_SaveChromeDeveloperConsoleLog%" equ "DEBUG"
,会生成一系列调试消息,但前提是环境变量 _SaveChromeDeveloperConsoleLog
已定义且值为 DEBUG
。 由于 _SaveChromeDeveloperConsoleLog
仅在需要时定义,因此此块什么也不做,除非您通过定义和设置它来启用它。
最后一个括号块中的倒数第二个语句,set "%~1=%fnglob%"
,负责通过定义一个名为第一个参数的第一个参数的环境变量,并将其值赋给本地环境变量 fnglob
来返回该值。必需加引号,但自从我发明这个技巧以来已经很久了,我早已忘记了原因。
最后一个命令是 exit /b
,其中 /b
指示命令处理器返回到调用脚本,类似于大多数“真正”编程语言中的 return
。不带参数的 exit 命令会退出整个脚本,而不是预期的结果!
exit /b
的替代方法是 goto :eof
,其中 eof
是一个虚拟标签,存在于脚本的最后一行文本之后。我两者都使用,尽管我最近的子例程更倾向于使用 exit
,因为我认为它更清晰一些。
我将用这些批处理文件中的每一个的几个特性来总结这一节。
@echo off
goto SKIPREM
-
每个脚本都以显示的两个命令开头,第一个命令抑制命令回显,包括它本身,下一行跳转到脚本标签
SKIPREM
,这是一个我几乎总是使用的标准标签。 - 立即跳转到
SKIPREM
使我能够在脚本顶部包含一个漂亮的注释块,包括修订历史记录,并且它允许在脚本顶部包含任意数量的函数(子例程),而不是在末尾,这是一种常见的做法。 SKIPREM
标签后的第一个命令始终是echo BOJ %~0, version %~t0
,它会宣布批处理文件的名称(如果有引号则去除),后跟一个由脚本文件最后修改日期组成的永久版本号。- 我的大多数脚本(但不是全部)接下来会调用
ShowTime.CMD
,它会显示当前日期和时间。它不是最完善的显示,因为它根本不调整字符串,但它很有效。 - 最后,
StartAngularApp.CMD
和StartAngularDevWebServer.CMD
多次调用 Node 包管理器和各种 node.js 包,这些包实际上是 Windows NT 命令脚本。为了防止它们过早终止,这些调用必须使用CALL
命令。启动 Visual Studio Code 编辑器的code
命令也是如此,它也是一个命令脚本。
历史
2017 年 4 月 26 日星期三是首次发布日期。