Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Node.js

Shell Scripts for an Angular 2 Toolbox

5.00/5 (1 vote)
25 Apr 2017CPOL7 min read 9.7K   50  
This article describes a handful of powerful shell scripts that I use to further automate my Angular 2 application development.

Introduction

Even the most robust, well designed development environments almost always can stand a bit more automation.

As I moved past the tutorial, it took me almost no time to realize that I could significantly streamline the work with a dose of automation, in the form of shell scripts (Windows NT command scripts).

Background

Throughout my long development career, I have endeavored to automate as many of the repetitive, error prone chores that take my attention away from the task at hand, especially those that involve steps that must be completed in a specific order. In the beginning, this automation consisted of little IBM JCL (Job Control Language) decks that I kept in my personal code repository. When I started working with personal computers, those JCL decks were replaced with batch files (now sometimes called shell scripts or Windows NT Command Scripts).

Over the last 5 years or so, it has become fashionable to use PowerShell for these kinds of tasks. Although I am quite confortable writing programs in C#, some of which found their way into this tool kit, PowerShell has a very steep learning curve, and is poorly suited to everyday use, unless you have ready access to commercial code signing certificates, and are willing to invest the time to use them in all of your scripts. Workarounds exist, but, by the time I could implement any of them, I could have my Windows NT command script written, tested, and in prodduction.

The package that accompanies this article contains nine shell scripts and programs (a mix of 32 bit native and managed code) that I use in my Angular work, summarized in the following table.

Tools in the Set
FileNameDescription
Date2FN.exeAppend LastWriteTime to file name.
LSNEWEST.BATReturn the name of the newest file that matches a wildcard specification. Several other scripts call this script.
MAKEZIP_DAG.CMDUse either WinZip or PK-Zip to make a backup archive of a directory.
SaveChromeDeveloperConsoleLog.CMDRun this script from a shortcut that sets its working directory to the directory where you want your collection of Chrome console logs. When you save the log, name it localhost.log; this script makes each file name unique.
StartAngularApp.CMDRun this script from a shortcut that sets its working directory to the directory where you created the Angular 2 application on which you want to work. The script will find the application source files extracted from the seed.
StartAngularDevWebServer.CMDBoth CreateNewAngularApp.CMD and StartAngularApp.CMD use this script to launch the Web server that comes with the Angular CLI. Since I haven't finished testing it, CreateNewAngularApp.CMD is omitted.
WWPause.exeThis robust replacement for the internal PAUSE command answers only to a Carriage Return or a CTRL-C.
wwsleep.EXEThis program is similar to sleep.exe, except that its memory footprint is quite a bit smaller.

There are two substantially identical Excel documents in the package.

  1. ToolboxInventory_Compact.XLSX contains one worksheet that is configured to show only the scripts and programs that you actually run.
  2. ToolboxInventory.xlsx contains one worksheet that lists evertyhing in the package, including the helper DLLs.

Both workbooks actually contain the same information, but ToolboxInventory_Compact.XLSX hides everything except the programs that you actually use. I'll leave you to discover for yourself how I did that.

Using the code

Most of the Windows NT command scripts are intended to be wired up to desktop shortcuts that leverage their Working Directory ("start in") properties to set the default directory against which to resolve relative path references.

Date2FN.exeWWPause.exe, and wwsleep.EXE are general purpose utility programs that can be put to all sorts of uses. I have many other scripts that use all three, and Date2FN.exe is pretty handy on its own as a command line utility.

Points of Interest

Classic batch file LSNEWEST.BAT is fairly straightforward. Its most unusual aspect is that it takes its input and returns its output through an environment variable, LSNEWEST, and that it uses the same varible for both. This is mostly a matter of engineering convenience, since environment variables are the only facility avaiilble for returning results from a function (subroutine).

BAT
dir "%LSNEWEST%" /b /od > %TEMP%\LSNEWEST.TMP
for /f %%i in (%TEMP%\LSNEWEST.TMP) do set LSNEWEST=%%i
del %TEMP%\LSNEWEST.TMP
  1. The filespec in environment string LSNEWEST is fed to the internal dir command, which is instructed to return a bare listing of file names, sorted from oldest to newest by modified date.
  2. The list is read from %TEMP%\LSNEWEST.TMP, and LSNEWEST is updated with the file name, so that it contains the name of the newest file when control falls through the loop.
  3. The file list has done its job, and is discarded.

The %TEMP% environment variable holds the name of the user's temporary (scratch) directory, which is guaranteed to be writeable.

You will probably wire SaveChromeDeveloperConsoleLog.CMD up to a desktop shortcut. In addition to treatomg LSNEWEST.BAT as a subroutine, it calls an internal subroutine, fnglob, which takes two parameters, as follows.

BAT
call :fnglob LSNEWEST %SRCFN%

The first argument is LSNEWEST, a string literal, while SRCFN stores the value of the first (and only) argument, if any, or a default name for the Chrome console log, localhost.log. When fnglob returns, LSNEWEST has been transformed into an environemnt string of the same name that holds the glob that LSNEWEST.BAT needs.

Since it gets expanded as it passes into the subroutine, SRCFN, keeps its normal bounding tokens.

BAT
Date2FN.exe -r !SRCFN!
call LSNEWEST.BAT
start !LSNEWEST!

While the unexpanded strings may be safely passed into fnglob, the next rhee commands require the delayed expansions imposed by the exclamation point tokens.

Function fnglob is mostly straightforward.

BAT
: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
)

The two strings that appear in angle brackets next to the function's name, <pglob> <pfilename>, are parameters, which the batch file treats as comments.

Protected by another expansion delayed setlocal block, fnpath and fnextn are set to the input filespec up to the extension and the extension, itself, respectively. The next command constructs the string that becomes the value of the third environment variable, fnglob.

The code within the If block, if "%_SaveChromeDeveloperConsoleLog%" equ "DEBUG", generates a series of debugging messages, but only when environment variable _SaveChromeDeveloperConsoleLog is defined and has a value of DEBUG.  Since _SaveChromeDeveloperConsoleLog is defined only as needed, this block does nothing, unless you turn it on by defining and setting it.

The next to last statement in the final parenthetical block, set "%~1=%fnglob%", is responsible for returning the value by defining an environment variable with the name given in the first argument, and assigning to it the value of local environment variable fnglob. The enclosing quotations are required, but it's been so long since I devised this trick that I have long since forgotten why.

The last command is exit /b, where the /b instructs the command processor to return to the calling script, similar to return in most "real" programming languages. Unadorned, the exit command exits the entire script, not the intended outcome!

An alternative to exit /b is goto :eof, where eof is a virtual label that exists just past the last line of text in the script. I use both, although my more recent subrotines tend toward exit, because I think it's a tad clearer.

I'll wrap this section up with a couple of features of every one of these batch files.

BAT
@echo off
goto SKIPREM
  1. Every script begins with the two commands shown above, the first of which suppresses command echo, including itself, and the next line goes to a script label, SKIPREM, a standard label that I almost always use.
  2. Jumping immediately to SKIPREM allows me to include a nice block of comments at the top of the script, including a revision history, and it permits any number of functions (subroutines) to be included at the top of the script, rather than at the end, as is a common proactice.
  3. The first command following the SKIPREM label is always echo BOJ %~0, version %~t0, which announces the name of the batch file, stripped of enclosing quotation marks, if any, followed by an evergreen version number comprised of the last modified date of the script file.
  4. Most, but by no means all, of my scripts next call ShowTime.CMD, which displays the current date and time. It's not the most polished display, because it doesn't bother to tweak the string at all, but it's effective.
  5. Finally, StartAngularApp.CMD and StartAngularDevWebServer.CMD make several calls into the Node Package Manager and variisous node.js packages, which happen actually to be Windows NT command scripts. To prevent their premature termination, these invocations must use CALL commands. The same goes for the code command that starts the Visual Studio Code editor, also a command script.

History

Wednesday, 26 April 2017 is the initial publication date.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)