Edit: 2022-01-06 (fixed a typo; thanks to Peter Coghlan)
In the 1980s, there were several companies claiming ownership of UNIX. Around this time, MIT programming guru Richard Stallman proposed rewriting all UNIX software which would be put it into the public domain. He called his project GNU which is a recursive (self referential) acronym which stands for Gnu Not Unix.
As part of HP's Unix Portability Initiative for OpenVMS, lots of UNIX code was ported to OpenVMS including GNU which was renamed to GNV (Gnv Not Vms). You can't say programmers don't have a sense of humor.
note: GNV-3.0-1 is further down this page
Legend:
<ur> user response (what you type)
<sr> system response (what you should see)
First, a little DCL to see what version of GNV is installed on your VMS system.
<sr> $ ! this is my DCL prompt
<ur> prod show prod gnv ! display installed products on your system
<sr> ------------------------------------ ----------- ---------
PRODUCT KIT TYPE STATE
------------------------------------ ----------- ---------
DEC AXPVMS GNV V2.1-3 Full LP Installed
------------------------------------ ----------- ---------
1 item found
$
Okay if GNV is installed then the BASH command should work<sr> $ ! this is my DCL prompt <ur> bash ! we are starting BASH in the GNC environment <sr> tcgetattr called tcgetattr called bash$ # this is my BASH prompt <ur> exit # exit this shell <sr> $ ! we are back to DCL
I don't hate UNIX/Linux command shells, I just prefer DCL (Digital Command Language). Why? In the VMS environment there is only one DCL (with a single early variant) to learn but in the UNIX/Linux world there are at least a dozen shells which go by names like:
This situation was so messy that UNIX programmers developed something called the sharp-bang hack (also known as shebang) so scripts requiring a specific shell could invoke it (providing the shell was not already running). Here is an example script:
Caveat: remember that the sharp-bang hack only works on line #1 of your script.
#!/bin/sh # ========================================================= # title : demo.sh # author : Neil Rieck # created: 1999-12-31 # caveat : this script only runs under the Bourne Shell # ========================================================= echo "Starting demo.sh"
comment: Canadians might have named this the octothorpe-exclamation hack which is much more accurate and the abbreviation would be known as octex
Fortunately, UNIX shells only come in four general flavors, and there is only one UNIX shell on VMS which is called BASH:
1 | Bourne Shell |
Oldest and simplest shell written by Steve Bourne at Bell Labs. There are numerous Bourne-like shells. Local shell variable declaration example: yada=hello Environment variable declaration examples: 1. export yada (promotes local shell variable to global) 2. export yada=hello (creates a variable then promotes it in one labor saving command) Invoked by executing command: /bin/sh comment: since it is called the Bourne Shell then why didn't they invoke it with "/bin/bs" rather than "/bin/sh" ??? |
2 | Korn Shell |
Written by Dave Korn at Bell Labs, this is a Bourne shell with a zillion additional features. There are multiple Korn-like shells. Local shell variable declaration example: yada=hello Environment variable declaration examples: 1. export yada (promotes local shell variable to global) 2. export yada=hello (creates a variable then promotes it in one labor saving command) Invoked by executing command: /bin/ksh |
3 | C Shell |
Written by Bill Joy when he was at Berkeley, the c-shell requires much less memory so many UNIX Admins prefer it as
their default when logging onto a limping system There are a few shells resembling the C-Shell. Local shell variable declaration example: set yada=hello Environment variable declaration example: setenv yada=hello Invoked by executing command: /bin/csh |
4 | BASH | Bourne Again SHell
is published by the Free Software Foundation so
comes with GNU and GNV. People like this shell because it does almost everything asked of it. Local shell variable declaration examples: yada=hello set yada=hello ("set" is superfluous) Environment variable declaration examples: 1. export yada (promotes variable to Environment variable) 2. export yada=hello (creates a variable then promotes it in one labor-saving statement) Invoked by executing command: /bin/sh (same as Bourne Shell above) |
VMS Environment (a review so we can discuss the UNIX environment)
In the VMS world, "environment variables" (originally a UNIX term) are stored two locations:
<ur> say :== write sys$output ! create DCL symbol (which is also an alias)
<sr> $ ! system displays prompt with no error message (so success)
<ur> say f$environment("default") ! use a lexical to display my current location
<sr> CSMIS$ROOT3:[USR.ADMCSM] ! system displays your current default directory
$ ! ...then displays a prompt with no error message (success)
<ur> set prompt = "neil> " ! change my prompt to something else
<sr> neil> ! system displays new prompt with no error message (success)
<ur> say f$environment("prompt") ! use a lexical to programmatically display my prompt
<sr> neil> ! system displays data from lexical "f$environment()"
neil> ! ...then displays prompt with no error message (success)
<ur> set prompt ="$ " ! restore my prompt back to default value
<sr> $ ! system displays prompt with no error message (success)
<ur> show log/process ! show process-level logical names <sr> (LNM$PROCESS_TABLE) "SYS$COMMAND" = "_KAWC99$NTA1:" <<<--- DCL get commands from here (my terminal) "SYS$DISK" = "CSMIS$USER3:" "SYS$ERROR" = "_KAWC99$NTA1:" <<<--- s/w sends errors here (my terminal) "SYS$INPUT" = "_KAWC99$NTA1:" <<<--- s/w gets data input here (my terminal) "SYS$OUTPUT" [super] = "_KAWC99$NTA1:" <<<--- s/w sends data output here (my terminal) "SYS$OUTPUT" [exec] = "_KAWC99$NTA1:" "TT" = "NTA1:" $ <ur> show log/job ! show job-level logical names <sr> (LNM$JOB_81EDFC40) "SYS$LOGIN" = "CSMIS$USER3:[ADMCSM.NEIL]" <<<--- my home directory "SYS$LOGIN_DEVICE" = "CSMIS$USER3:" "SYS$SCRATCH" = "CSMIS$USER3:[ADMCSM.NEIL]" $ <ur> create yada.com <<<--- create a file titled "yada.com" $write sys$output f$environment("PROCEDURE") <<<--- enter this DCL command into the file $show log/proc <<<--- enter this DCL command into the file <ctrl-z> <<<--- now hit <control-Z> to finish creation <sr> EXIT $ <ur> @yada.com <<<--- execute the DCL script <sr> CSMIS$USER3:[ADMCSM.NEIL]YADA.COM;1 <<<--- notice the current "PROCEDURE" name (LNM$PROCESS_TABLE) <<<--- this comes from "show log/proc" "SYS$COMMAND" = "_KAWC99$NTA1:" <<<--- can still do a <control-c> from here "SYS$DISK" = "CSMIS$USER3:" "SYS$ERROR" = "_KAWC99$NTA1:" "SYS$INPUT" [super] = "_KAWC99$DKA100:" <<<--- notice that SYS$INPUT has changed to disk name "SYS$INPUT" [exec] = "_KAWC99$NTA1:" "SYS$OUTPUT" [super] = "_KAWC99$NTA1:" "SYS$OUTPUT" [exec] = "_KAWC99$NTA1:" $
Each one of your processes will have its own PROCESS logical-name table but they will all share (and could communicate via) a common JOB logical-name table. Your process can also access information stored in GROUP, SYSTEM and CLUSTER name tables but this fact is beyond the scope of this introduction. DCL (a command interpreter which can also executes scripts) stores its variables in two symbol tables private to your process.
Local symbol declaration is done with a single equal sign ("=") while global symbol declaration is done with two equal signs ("=="). Placing a colon out in front is similar to quoted string declaration. Here are some rambling demos:
<ur> say == "write sys$output" ! this DCL symbol is similar to a UNIX alias <sr> $ ! system displays prompt with no error message (so success) <ur> say :== write sys$output ! this DCL symbol is similar to a UNIX alias <sr> $ ! system displays prompt with no error message (so success) <ur> write sys$output f$logical("sys$login") ! "write" is a DCL command <sr> CSMIS$USER3:[ADMCSM.NEIL] $ <ur> say f$logical("sys$login") ! "say" is a DCL symbol we defined above <sr> CSMIS$USER3:[ADMCSM.NEIL] $ <ur> set default sys$login ! this command works like the "cd" command in UNIX <sr> $
<ur> show symbol/glo/all ! show all global symbols <sr> $FACILITY == "%X00000003" $IDENT == "%X00001028" $RESTART == "FALSE" $SEVERITY == "0" $STATUS == "%X00038140" ED*IT == "EDIT/EDT" FTP == "$TCPWARE:FTP" PING == "$TCPWARE:PING" PING2 == "$TCPWARE:PING_V2" TELNET == "$TCPWARE:TELNET" $ <ur> say = "write sys$system" ! create local symbol (which is like a UNIX alias) <sr> $ ! system displays prompt with no error message (so success) <ur> say == "write sys$system" ! create global symbol (which is like a UNIX alias) <sr> $ <ur> show sym/loc s* ! show local symbols beginning with "s" <sr> SAY = "write sys$system" $ <ur> show sym/glo s* ! show global symbols beginning with "s" <sr> SAY == "write sys$system" $ <ur> yada = "hello" ! define a string variable called "yada" <sr> $ <ur> demo = 123 ! define a numeric variable called "demo" <sr> $ <ur> neil = "sys$login" ! define a string variable called "yada" <sr> $ <ur> say yada ! display the contents of the symbol "yada" <sr> hello $ <ur> say demo ! display the contents of the symbol "demo" <sr> 123 $ <ur> sho symbol demo ! show the contents of the symbol "demo" (different than display) <sr> DEMO = 123 Hex = 0000007B Octal = 00000000173 $ <ur> say neil ! <sr> sys$login $ <ur> dir 'neil' ! use the contents of "neil" in a directory command <sr> Directory CSMIS$USER3:[ADMCSM.NEIL] a.txt b.txt c.txt $
Warning: While installing new software, many installation scripts will delete all your symbols before they begin. This in done so that your aliases don't interfere with the installation script.
$ del /symbol/all !So if you've just invoked @sys$update:vmsinstal or $product install then find that your process is not behaving as expected, you might wish to log off then back out to restore your symbol environment.
UNIX Environment
In UNIX/Linux each shell instance supports two variable tables: Environmental and Symbol. Scripts store their variables in the symbol table while important stuff, like your terminal device name, goes into the environmental table.
In the "C" shell, these two tables are manipulated using different commands.
In most other shells...
Executing a shell script in UNIX actually spawns a new process. This means that anything changed by the script (including setting variables or changing your default directory) will be only happen in that spawned process. Once the script exits, the spawned process is destroyed and you will be auto-magically dropped back to the original process. This means that you will not be able to use a script to make quick temporary changes unless you export your changes from the local symbol table to the environmental table.
So once you think you know "global" variables from "local" variables, BASH introduces a new command called "local" which is only used to "create a variable which is local to a function". When will the madness end?
Why would we ever want a UNIX shell on OpenVMS. Well, take a peek into directory "AXIS2$ROOT:[bin]" and you will see two scripts:
$ dir wsdl2*/date/size Directory DISK$USER1:[000000.axis2.bin] wsdl2java.bat;1 6 6-DEC-2007 13:22:08.79 <<<--- provided by AXIS2 team for Windows use wsdl2java.sh;1 2 6-DEC-2007 13:22:08.83 <<<--- provided by AXIS2 team for UNIX use Total of 2 files, 8 blocks.
The file with the ".bat" extension is meant for use on Windows while the other file with the ".sh" extension is meant for use on UNIX. Learn how to use GNV/BASH and you'll be able to run the UNIX script on OpenVMS. The Apache-AXIS2 team didn't think it was necessary to provide a DCL script (and would probably have confused the non-VMS world by publishing a script with a ".com" extension).
Documentation Caveat: for some reason the GNV package seems to be poorly tacked onto OpenVMS. It works properly if you already know what you are doing, but locating documentation can be troublesome. Here are a few beefs.
<sr> $ ! this is the default vms prompt
<ur> bash ! start the shell (enter the GNV environment)
<sr> bash$ # this is the default bash prompt
<ur> ls /psx\$root # remember to escape the dollar sign '$'
<sr> BIN DOC ETC INCLUDE LIB SRC USR dev home man mnt tmp
bash$
<ur> ls /psx\$root/man/ # see man files
<sr> bash$ # (none)
<ur> ls /psx\$root/doc/ # see doc files
<sr> GNVREADME_FIRST.HTML GNVREADME_FIRST.TXT GNVREADME_FIRST_003.HTML
GNVREADME_FIRST.PDF GNVREADME_FIRST_001.HTML GNVREADME_FIRST_CONTENTS.HTML
GNVREADME_FIRST.PS GNVREADME_FIRST_002.HTML RELEASE_NOTES.TXT
bash$
<ur> cat /psx\$root/doc/RELEASE_NOTES.TXT # view
<sr> [...snip...] #
<ur> ls /psx\$root/bin/ # see bin files
<sr> [...snip...] # most of these files are shell applications
bash$
<ur> ls -la /psx\$root/bin/u* # see all files beginning with letter 'u'
<sr> -rwxr-xr-x 1 SYSTEM 1 30208 Nov 3 2011 /psx$root/bin/umnt
-rwxr-xr-x 1 SYSTEM 1 33792 Nov 3 2011 /psx$root/bin/uname
-rwxr-xr-x 1 SYSTEM 1 36864 Nov 3 2011 /psx$root/bin/unexpand
-rwxr-xr-x 1 SYSTEM 1 46592 Nov 3 2011 /psx$root/bin/uniq
-rwxr-xr-x 1 SYSTEM 1 215552 Nov 3 2011 /psx$root/bin/unzip
-rwxr-xr-x 1 SYSTEM 1 120320 Nov 3 2011 /psx$root/bin/unzipsfx
bash$
<ur> ls -la /psx\$root/bin/v* # see all files beginning with letter 'v'
<sr> -rwxr-xr-x 1 SYSTEM 1 154112 Nov 3 2011 /psx$root/bin/vdir
-rwxr-xr-x 1 SYSTEM 1 12800 Nov 3 2011 /psx$root/bin/vi
-rwxr-xr-x 1 SYSTEM 1 3381760 Nov 3 2011 /psx$root/bin/vim
-rwxr-xr-x 1 SYSTEM 1 48640 Nov 3 2011 /psx$root/bin/vmstar
bash$
<sr> $ <ur> dir psx$root:[000000] <sr> Directory PSX$ROOT:[000000] BIN.DIR;1 dev.DIR;1 DOC.DIR;1 ETC.DIR;1 home.DIR;1 INCLUDE.DIR;1 LIB.DIR;1 man.DIR;1 mnt.DIR;1 SRC.DIR;1 tmp.DIR;1 USR.DIR;1 Total of 12 files. $ <ur> KAWC99::Neil> dir psx$root:[bin]u* <sr> Directory PSX$ROOT:[BIN] umnt.;2 UMNT.EXE;1 uname.;2 UNAME.EXE;1 unexpand.;2 UNEXPAND.EXE;1 uniq.;2 UNIQ.EXE;1 unzip.;2 UNZIP.EXE;1 unzipsfx.;2 UNZIPSFX.EXE;1 Total of 12 files. $
High Value GNV-related Documents:
The Bourn Again Shell (BASH) comes with HP's GNV package which you should consider installing if you want to develop middleware on the OpenVMS platform. There are many differences between DCL and BASH but I'm only going to describe a few things about DCL symbols (BASH variables)
command | DCL | BASH | Notes |
---|---|---|---|
declare a local symbol | yada = "HELLO" | yada=HELLO | The BASH command must not include a space |
declare a global symbol | yada == "HELLO" | export yada (yada must already exist) |
these commands have "slightly" different meanings |
reference a symbol | write sys$output yada | echo $yada echo ${yada} |
informal method formal method |
declare a symbol with dollar | yada = "sys$login" | yada=sys\$login | since a dollars is used to dereference a BASH symbol, you must escape them with a backslash |
this will only work from within a BASH script:
set yada=this\ is\ a\ test
echo $yada
but from BASH command line you must type this:
export yada=this\ is\ a\ test
echo $yada
why? everything executable from the command line forks a new process
(but not commands like: source (to only name one of many)
!============================================================================== ! using GNV on OpenVMS to run AXIS2 tools like "WSDL2Java.sh" ! ! 1) GNV must be installed to use bash ! 2) this example works with JAVA5 (a.k.a. Java 1.5) ! 3) dollar symbols must be escaped ("\") ! 4) the first DCL command learns where JAVA is installed ! 5) Legend: <ur> = user response (what YOU typed) ! <sr> = system response (what the system displayed) !============================================================================== <ur> @SYS$MANAGER:JAVA$150_SETUP.COM ! init Java for this process <sr> $ ! <ur> show sym javac ! see where Java lives <sr> JAVAC == "$ SYS$COMMON:[JAVA$150.bin]java$javac" ! this symbol can only be used by DCL $ ! <ur> set term/wrap ! <sr> $ ! <ur> set def AXIS2$ROOT:[000000.BIN] ! navigate to here <sr> $ ! <ur> bash ! start BASH <sr> bash$ # <ur> echo $JAVA_HOME # see current definition of JAVA_HOME <sr> bash$ # <ur> JAVA_HOME=/SYS\$COMMON/JAVA\$150/ # define JAVA_HOME (notice the backslashes escaping the dollars) <sr> bash$ # <ur> export JAVA_HOME # make it global <sr> bash$ # <ur> echo $JAVA_HOME # ensure still defined (use dollar to dereference the variable) <sr> /SYS$COMMON/JAVA$150/ # bash$ # <ur> ls -la # get a detailed directory <sr> total 48 -rwxrwxrwx 1 APACHE$W 128 27256 Aug 12 12:00 INCIDENT.WSDL -rwxr-xr-x 1 APACHE$W 128 2771 Jul 7 11:53 axis2.bat -rwxr-xr-x 1 APACHE$W 128 1669 Jul 7 11:53 axis2.sh -rwxr-xr-x 1 APACHE$W 128 2942 Jul 7 11:53 axis2server.bat -rwxr-xr-x 1 APACHE$W 128 1270 Jul 7 11:53 axis2server.sh -rwxr-xr-x 1 APACHE$W 128 2777 Jul 7 11:53 java2wsdl.bat -rwxr-xr-x 1 APACHE$W 128 688 Jul 7 11:53 java2wsdl.sh -rwxr-xr-x 1 APACHE$W 128 3325 Jul 7 11:53 setenv.sh -rwxr-xr-x 1 APACHE$W 128 2708 Jul 7 11:53 wsdl2java.bat <<<--- provided by AXIS2 team for Windows use -rwxr-xr-x 1 APACHE$W 128 686 Jul 7 11:53 wsdl2java.sh <<<--- provided by AXIS2 team for UNIX use bash$ # <ur> mkdir ./yada # <sr> bash$ # <ur> wsdl2java.sh -? # execute the desired script <sr> { help is displayed } # <ur> wsdl2java.sh -uri INCIDENT.WSDL -o ./yada # execute the desired script <sr> Using AXIS2_HOME: /AXIS2$ROOT Using JAVA_HOME: /SYS$COMMON/JAVA$150/ [INFO] The ./yada/src/devenvironment/amx/Dispatcher_100201007131331_serviceBinding_ IncidentInService_IncidentBLInbound_IncidentBLSOAPServiceBindingStub.java file cannot be overwritten. bash$ #
GNV is a work in progress and is getting more UNIX-like every release. The first release of GNV did a really good job processing VMS-style file specifications and a not so good job of processing UNIX-style file specifications. As time goes on, you will be expected to deal with only UNIX-style file specs. This will be done by mounting VMS volumes into the POSIX root.
The built-in help for mnt and umnt are terrible and this may be because these commands are still a work in progress (at least from an OpenVMS point of view). You can learn more about these commands by searching through scripts located in SYS$STARTUP especially:
! Legend: <ur> = user response (what YOU typed) ! <sr> = system response (what the system displayed) ! Note: DISK$USER1 is a logical pointing to disk KAWC99$DRA1: !============================================================================== <sr> $ ! this is our DCL prompt <ur> dir psx$root:[000000] ! see what is in our posix root <sr> Directory PSX$ROOT:[000000] BIN.DIR;1 dev.DIR;1 DOC.DIR;1 ETC.DIR;1 home.DIR;1 INCLUDE.DIR;1 LIB.DIR;1 man.DIR;1 mnt.DIR;1 SRC.DIR;1 USR.DIR;1 $ <ur> dir psx$root:[mnt] ! see what is in posix/mnt <sr> %DIRECT-W-NOFILES, no files found $ <ur> sho dev d/mount ! see our disks <sr> Device Device Error Volume Free Trans Mnt Name Status Count Label Blocks Count Cnt KAWC99$DRA0: Mounted 0 ALPHASYS 15205120 463 1 KAWC99$DRA1: Mounted 0 CSMISUSER1 21715760 167 1 $ <ur> bash ! invoke bash <sr> bash$ # this is our BASH prompt <ur> mnt # see what is mounted <sr> DISK$ALPHASYS:[000000]PSX$ROOT.DIR;1 on disk$alphasys:[vms$common.gnv] bash$ <ur> mnt -v -F KAWC99\$DRA1:[000000] /mnt # see how I escaped the dollar symbol? <sr> mnt version V2.8 mnt: Mounted: DISK$USER1:[000000] on /mnt bash$ # # DISK$USER1 came up because that is the VMS mount logical for disk DRA1: # <ur> mnt # see what is mounted <sr> DISK$USER1:[000000] on /mnt DISK$ALPHASYS:[000000]PSX$ROOT.DIR;1 on disk$alphasys:[vms$common.gnv] bash$ <ur> ls /mnt <sr> BACKUP.SYS CORIMG.SYS CSMIS BADBLK.SYS INDEXF.SYS BADLOG.SYS SAVESETS BITMAP.SYS SECURITY.SYS CONTIN.SYS VOLSET.SYS bash$ <ur> exit # leave GNV/Bash <sr> $ <ur> dir psx$root:[mnt] ! see what is in posix/mnt <sr> Directory PSX$ROOT:[mnt] 000000.DIR;1 BACKUP.SYS;1 BADBLK.SYS;1 BADLOG.SYS;1 BITMAP.SYS;1 CONTIN.SYS;1 CORIMG.SYS;1 CSMIS.DIR;1 INDEXF.SYS;1 SAVESETS.DIR;1 SECURITY.SYS;1 VOLSET.SYS;1 $ ! oops we didn't want this mess. ! It is okay for one disk volume but no good for two or more. ! Let's undo everything. !============================================================ <ur> bash ! invoke bash <sr> bash$ # this is our BASH prompt <ur> umnt -v /mnt # unmount this whole file system <sr> umnt version V2.8 umnt: Unmounted: DISK$USER1:[000000] on /mnt bash$ # no errors so all went well <ur> mnt # see what is mounted <sr> DISK$ALPHASYS:[000000]PSX$ROOT.DIR;1 on disk$alphasys:[vms$common.gnv] bash$ <ur> exit # leave GNV/BASH <sr> $ <ur> dir psx$root:[mnt] ! see what is in posix/mnt <sr> %DIRECT-W-NOFILES, no files found $
We need a script which will make the necessary directory entries into PSX$ROOT:[mnt]
$!====================================================================
$! title : mnt_hack.com
$! author : Neil Rieck
$! edit : 2011-03-13
$! notes : For pedagogical use only. This is not a production script.
$! params : P1 = POSIX filespec
$! P2 = VMS device name
$! example: @mnt_hack "CSMISUSER1" "DRA1"
$!====================================================================
$ say := write sys$output
$ dq[0,8]=34
$ say "mnt_hack"
$ say "========"
$ if p1 .eqs. ""
$ then
$ say "-e- oops, missing P1 (POSIX filespec)"
$ goto display_help
$ endif
$ if p2 .eqs. ""
$ then
$ say "-e- oops, missing P2 (vms device)"
$ goto display_help
$ endif
$ p1 = p1 - ":" - ":" - ":" -":" ! no colons for now
$! List existing mount points.
$ mnttmpfile = "sys$scratch:psx$$start.tmp;"
$ define/user sys$output 'mnttmpfile'
$ mnt
$! Append a space to each line to remove ambiguity from the search.
$ close/nolog tin
$ open/read tin 'mnttmpfile' /error=write_anyway
$write_anyway:
$ close/nolog tout
$ open/write tout 'mnttmpfile'
$mnt_top:
$ read tin line /error=mnt_bot
$ write tout "''line' "
$ goto mnt_top
$mnt_bot:
$ close tin /error=close_out
$ close_out:
$ close tout
$!----------------------------------------
$ call DoOneMountpoint 'p1' 'p2'
$ del/nolog/noconf PSX$$START.TMP;*
$ exit
$display_help:
$ say "-i-example syntax:"
$ say " @mnt_hack ",dq,"CSMISUSER1",dq," ",dq,"DRA1",dq
$ say "-i-note: use double quotes to preserve case"
$ exit
$!===========================================================================
$! the following code was lifted from script:
$! sys$startup.com:PSX$UP_STARTUP.COM
$!===========================================================================
$DoOneMountpoint: subroutine
$!
$! Generate a mountpoint in /mnt/'P1' for P2
$!
$! P1 - Pseudo Device name
$! P2 - Real Device name or rooted directory spec
$!
$ mntpoint = p1
$ filesys = p2
$! Volume labels may have non-filename characters in them. Check.
$! Note that for some unusual characters, this will succeed and dirname
$! will have those characters quoted by a preceding ^ character.
$ dirname = f$parse("PSX$ROOT:[mnt]''mntpoint'.DIR;",,,"name","syntax_only")
$ if dirname .eqs. ""
$ then ! the volume name is syntactically objectionable, use the device name.
$ mntpoint = f$parse("PSX$ROOT:[mnt]''filesys'.DIR;",,,"name","syntax_only")
$ ! Dollar signs are common in VMS disk names, and though they are valid name
$ ! characters, but are annoying in Posix because the shells use $ to indicate
$ ! variable name substitution. Remove them for convenience.
$ mntpoint = mntpoint - "$" - "$" - "$" - "$"
$ endif
$ if f$parse("PSX$ROOT:[mnt]''mntpoint'.DIR;") .eqs. ""
$ then ! If that's not good, give up and say so.
$ write sys$output "Not creating mount point directory ""PSX$ROOT:[mnt.''mntpoint']"""
$ write sys$output "Fabricated directory name not valid."
$ exit
$ endif
$
$ if f$search ("PSX$ROOT:[mnt]''mntpoint'.DIR;") .eqs. ""
$ then
$ write sys$output "Creating directory ""PSX$ROOT:[mnt.''mntpoint']"""
$ create/dir /OWNER=SYSTEM/PROT=(S:REW,O:REW,G:REW,W:RE) PSX$ROOT:[mnt.'mntpoint']
$ endif
$
$! Have we already done this one?
$!!! Oops. Avoid bug from this call.
$!! if filesys .eqs. (f$file("PSX$ROOT:[mnt]''mntpoint'.DIR","dvi") - "_" - ":") .and. -
$!! "(4,4,0)" .eqs. f$file("PSX$ROOT:[mnt]''mntpoint'.DIR","fid") -
$!! then exit
$! Have we already got this mounted?
$ search /output=nl:/nowarnings 'mnttmpfile' " on /mnt/''mntpoint' "
$ if $status .eq. 1 then exit ! It is already there, so pass.
$
$ on error then continue
$ ! v = f$verify (1)
$ mnt -v 'filesys':[000000] PSX$ROOT:[mnt.'mntpoint']
$ if .not. $status then delete PSX$ROOT:[mnt]'mntpoint'.DIR;1 /log
$ ! f$verify (v)
$ on error then exit
$ ! If that didn't work, the message printed by mnt will be sufficient.
$ exit
$ endsubroutine ! DoOneMountpoint
! Legend: <ur> = user response (what YOU typed) ! <sr> = system response (what the system displayed) ! Note: gnv/bash commands mnt and umnt will be executed from DCL !============================================================================== <sr> $ ! this is my DCL prompt <ur> @mnt_hack ! no params to force help mnt_hack ======== -e- oops, missing P1 (POSIX filespec) -i-example syntax: @mnt_hack "CSMISUSER1" "DRA1" -i-note: use double quotes to preserve case $ <ur> @mnt_hack "CSMISUSER1" "DRA1" <sr> mnt_hack ======== mnt version V2.8 mnt: Mounted: DISK$USER1:[000000] on /mnt/CSMISUSER1 $ <ur> bash ! leave DCL <sr> bash$ <ur> mnt # see what is mounted <sr> DISK$USER1:[000000] on /mnt/CSMISUSER1 DISK$ALPHASYS:[000000]PSX$ROOT.DIR;1 on disk$alphasys:[vms$common.gnv] bash$ <ur> ls /mnt/CSMISUSER1 # get a directory <sr> BACKUP.SYS CORIMG.SYS CSMIS BADBLK.SYS INDEXF.SYS BADLOG.SYS SAVESETS BITMAP.SYS SECURITY.SYS CONTIN.SYS VOLSET.SYS bash$ <ur> umnt -v /mnt/CSMISUSER1 # restore to original state <sr> umnt version V2.8 umnt: Unmounted: DISK$USER1:[000000] on /mnt/CSMISUSER1 bash$ <ur> mnt # see what is mounted <sr> DISK$ALPHASYS:[000000]PSX$ROOT.DIR;1 on disk$alphasys:[vms$common.gnv] bash$ <ur> exit # back to DCL <sr> ?
Caveat: this package requires VMS-8.3 or higher
Installation Problems
I've got two fully patched OpenVMS-8.4 Alpha systems but cannot install GNV-3.0-1 on either of them. After unzipping the download, the installation fails at the kit validation step like so:
$ prod inst gnv
1 - DEC AXPVMS GNV V3.0-1 Layered Product
2 - DEC AXPVMS GNV V2.1-3 Layered Product
? - Help
E - Exit
Choose one or more items from the menu: 1
Performing product kit validation of signed kits ...
%PCSI-E-VALFAILED, validation of KAWC99$DRA1:[CSMIS.USR.][ADMCSM.NEIL]DEC-AXPVMS-GNV-V0300-001-1.PCSI$COMPRESSED;3 failed
-PCSI-E-HPC_TEXT, validate_finalize: Verification of signed file failed
%PCSIUI-E-ABORT, operation terminated due to an unrecoverable error condition
$
I only know of three ways to get around this problem:
1) Unzip again but make sure you use the "-b switch
unzip -b DEC-AXPVMS-GNV-V0300-001-1.ZIPNote: click OpenVMS Notes: UNZIP to learn why you should always unzip this way on OpenVMS systems.
2) Fix file attributes like so:
set file/attribute=(rfm:fix,lrl:512,mrs:512,org:seq,rat:none) DEC-AXPVMS-GNV-V0300-001-1.PCSI$COMPRESSED
3) Install the kit without validation (not recommended unless it is an emergency):
prod inst gnv /option=novalid
The other day some poor devil who was looking to spend more time in purgatory asked me how to edit a file from within BASH. Since I had been using EDT since the early 1980s on RT-11 and RSX-11, I told him to exit BASH then just use EDIT/EDT from a DCL prompt.
Truth be told, there is no way any self respecting IT professional can exist today without being able to use VI. Someday soon, every VMS person will find themselves on a UNIX or Linux platform with no editor other than VI. (This happens to me all the time, especially when working with contractors; IT life this side of y2k finds us living in a world where the next generation has not taken the time to learn a character-cell editor)
Personal Comments:
The neat thing about BASH on VMS is that unrecognized commands in BASH are handed off to DCL (this behavior can be disabled by executing this command: export GNV_DISABLE_DCL_FALLBACK=1). So just typing EDIT from within BASH will usually bring the default editor (usually EVE) unless you have redefined the symbol. My login.com (or sys$manager:sylogin.com) always creates a symbol to redirect EDIT to EDIT/EDT like so:
$! $! login.com $! $ ED*IT == edit/edt
Just a few basics (buy a used copy of "UNIX for DUMMIES" and "More UNIX for DUMMIES" to dig deeper)
command | action | |
---|---|---|
hit | : | drop last line mode |
hit | arrow keys | move your cursor to some point of interest |
hit | i | switch to insert mode at cursor position (insert) |
hit | a | switch to insert mode after cursor position (a.k.a. append) |
hit | x | delete the character under the cursor (moves to paste buffer) |
hit | dd | delete the current line (goes into the paste buffer) |
hit | p | pastes from the buffer |
type | /hello<enter> | forward find "hello" |
hit | n | next (repeat previous find) |
type | ?hello<enter> | reverse find "hello" |
hit | <ctrl-g> | where am I right now |
type | 9<shift-g> | go to line 9 |
type | 9x | erase next 9 characters (all go into the paste buffer) |
type | 9dd | delete the next 9 lines (all go into the paste buffer) |
type | y | copies one character into the paste buffer |
type | 9y! | copes next 9 characters into the paste buffer |
type | 9yy | copies next 9 lines into the paste buffer |
command | action | |
---|---|---|
type | what ever you wish | this is your inserted data |
hit | <escape> | drop back to cursor positioning mode |
command | action | |
---|---|---|
type | q<enter> | quit; you will be warned if unsaved changes are in the buffer |
type | q!<enter> | quit; you will NOT be warned if unsaved changes are in the buffer |
type | w<enter> | write the buffer to disk |
type | wq<enter> | write then quit |
type | help<enter> | fails with help file not found |
Command | Action | |
---|---|---|
hit | v | enter visual character mode (use arrow keys to adjust) |
hit | V | enter visual line mode (use arrow keys to adjust) |
hit | <ctrl-v> | enter visual block mode (use arrow keys to adjust) |
hit | y | yank (copy highlighted data into the buffer) |
hit | p | paste from buffer |
hit | u | undo previous command |
hit | <ctrl-r> | redo |
type | :set<enter> | to view current editor settings |
type | :set term=vt999<enter> | to see legal terminal settings |
type | :set term=vt320<enter> | to set to vt320 |
<sr> bash$ <ur> vim -h # get help from the VIM editor <sr> VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Nov 3 2011 03:20:41) usage: vim [arguments] [file ..] edit specified file(s) or: vim [arguments] - read text from stdin or: vim [arguments] -t tag edit file where tag is defined or: vim [arguments] -q [errorfile] edit file with first error Where case is ignored prepend / to make flag upper case Arguments: -- Only file names after this --literal Don't expand wildcards -v Vi mode (like "vi") -e Ex mode (like "ex") -s Silent (batch) mode (only for "ex") -d Diff mode (like "vimdiff") -y Easy mode (like "evim", modeless) -R Readonly mode (like "view") -Z Restricted mode (like "rvim") -m Modifications (writing files) not allowed -M Modifications in text not allowed -b Binary mode -l Lisp mode -C Compatible with Vi: 'compatible' -N Not fully Vi compatible: 'nocompatible' -V[N][fname] Be verbose [level N] [log messages to fname] -D Debugging mode -n No swap file, use memory only -r List swap files and exit -r (with file name) Recover crashed session -L Same as -r -A start in Arabic mode -H Start in Hebrew mode -F Start in Farsi mode -T <terminal> Set terminal type to <terminal> -u <vimrc> Use <vimrc> instead of any .vimrc --noplugin Don't load plugin scripts -p[N] Open N tab pages (default: one for each file) -o[N] Open N windows (default: one for each file) -O[N] Like -o but split vertically + Start at end of file +<lnum> Start at line <lnum> --cmd <command> Execute <command> before loading any vimrc file -c <command> Execute <command> after loading the first file -S <session> Source file <session> after loading the first file -s <scriptin> Read Normal mode commands from file <scriptin> -w <scriptout> Append all typed commands to file <scriptout> -W <scriptout> Write all typed commands to file <scriptout> -x Edit encrypted files --startuptime <file> Write startup timing messages to <file> -i <viminfo> Use <viminfo> instead of .viminfo -h or --help Print Help (this message) and exit --version Print version information and exit bash$
<sr> bash$ # this is the BASH prompt <ur> vim -e yada.txt # start vim in "ex" mode using data file "yada.txt" <sr> "yada.txt" 39 lines, 2942 characters Entering Ex mode. Type "visual" to go to Normal mode. : # this is the "ex" prompt (remember, single line mode) <ur> 5<enter> # go to line 5 <sr> [...snip...] # line 5 data is displayed : # this is the "ex" prompt <ur> q<enter> # quit the editor <sr> bash$ # this is the BASH prompt
<sr> bash$ # <ur> vim -v yada.txt # start vim in "vi" mode using data file "yada.txt" <sr> [...snip...] # file contents are displayed <ur> :q<enter> # just quit <sr> bash$ # this is the BASH prompt
<sr> bash$ # <ur> vim # start vim <sr> [...snip...] # when no file is specified, primitive help is displayed <ur> :help<enter> # request help <sr> E433: No tags file E149: Sorry, no help for help.txt Press ENTER or type command to continue <ur> <enter> # acknowledge error message <ur> :q<enter> # just quit <sr> bash$ # this is the BASH prompt
<sr> bash$ # <ur> export VIM=/psx\$root/USR/SHARE/VIM/VIM73/ # vim needs to know where VIM resources exist <sr> bash$ # <ur> vim # when no file is specified, primitive help is displayed <sr> [...snip...] # primitive help is displayed <ur> :help<enter> # request help <sr> [...snip...] # help text is displayed <ur> :q<enter> # quit from help <ur> :q<enter> # just quit <sr> bash$ # this is the BASH prompt
<sr> $ ! <ur> show log *vim* !
"VIMRUNTIME" = "/psx$root/USR/SHARE/VIM/VIM73/runtime" <sr> $ !
use an editor to create/modify file: sys$login:.bashrc" (a file named ".bashrc" where "rc" = run command) then insert some/all of this shell script: echo "====================================" # echo "-i-starting: neil's .bashrc" # echo "-i-defining VIM" # export VIM=/psx\$root/USR/SHARE/VIM/VIM73/ # this one line does all the work echo "-i-VIM="$VIM # echo "-i-exiting: neil's .bashrc" # echo "====================================" #
Optional Stuff
Not sure which compiler is being used here:Hard core programmers might wish to make their DCL environment completely case sensitive before starting BASH and this is how you do it:
<sr> $ ! <ur> SET PROC/CASE=SENS/PARSE=EXTENDED ! now VMS is just like UNIX (case-wise) <sr> $ !But some systems will now be so messed up that you might not be able to log off so this is how you restore sanity:
<sr> $ ! <ur> SET PROC/CASE=BLIND/PARSE=TRADITION ! back to pre VMS-7.2 ways <sr> $ !
Let's get on with the program development demo:<sr> $ ! my DCL prompt <ur> cc /version ! first inspect my already installed C compiler <sr> HP C V7.3-009 on OpenVMS Alpha V8.4 ! $ <ur> bash # DCL -> bash <sr> bash$ <ur> cc --version # what version of c compiler? <sr> GNV Nov 14 2011 05:32:53 # perhaps some sort of wrapper? HP C V7.3-009 on OpenVMS Alpha V8.4 bash$ <ur> gcc -version # what version of gcc? <sr> GNV Nov 14 2011 05:32:53 # perhaps some sort of wrapper? HP C V7.3-009 on OpenVMS Alpha V8.4 bash$ <ur> gcc --help # what compiler switches are available <sr> [...snip...] # better see for yourself <ur> exit # back to DCL <sr> $
<sr> $ ! VMS prompt <ur> bash ! DCL -> bash <sr> bash$ # GNV/BASH prompt <ur> vim neil.c # use vi or vim to create a file # beware: this file is probably upper case
enter a program similar to this:
// // title: neil.c // #include <stdio.h> int main(int argc, char *argv[]){ // code to access command line args int rc; // return code int count; // arg counter printf("Hello Neil\n"); for (count=1;count<=argc;count++){ printf("%s %d %s\n","-i-arg:",count-1,argv[count-1]); } rc = 99; // this is just to test my logic printf("%s%d\n","exiting with code: ",rc); // return(rc); // in unix, 0 = "no error" }Now lets compile, link, then run it:
<ur> cc neil.c # compile program <sr> bash$ <ur> link neil.o # link program <sr> bash$ <ur> ./neil 123 456 # run the program (with optional params) <sr> Hello Neil -i-arg: 0 neil # image name -i-arg: 1 123 # p1 -i-arg: 2 456 # p2 exiting with code: 99 bash$ <ur> my_status=$? # save program exit status <sr> bash$ <ur> echo $my_status # show program exit code <sr> 123 bash$ #