getjobid, cl, and liblist — Oh, My!
With the latest update to BASH, there are 3 new IBM i-specific BASH builtin
getjobid. These builtins function nearly
identically to the
getjobid commands that exist in
PASE and/or QSH.
If these commands already exist, why add them to BASH? Let's explore:
$ /QOpenSys/usr/bin/getjobid Process identifier 1575015 is 073984/QSECOFR/QP0ZSPWT $ /QOpenSys/usr/bin/getjobid Process identifier 1575016 is 073985/QSECOFR/QP0ZSPWT $ /QOpenSys/usr/bin/getjobid Process identifier 1575017 is 073986/QSECOFR/QP0ZSPWT
Every time I run getjobid, I'm getting the job id of the
getjobid process, not
my shell's jobid. If I want to get my shell's job id, I have to remember to pass
the shell's pid (which is helpfully in the
$$ special variable)
Kind of a pain, but once you figure it out it's not sooooo bad.
CL to the Rescue?
Ok, so now let's say I am trying to run a PASE program which is running in to
problems while calling some ILE code. The ILE code is writing messages to the
job log, but the job log isn't being saved due to the log level of the job!
Let's use the
system command to change the log level:
/QOpenSys/usr/bin/system "CHGJOB LOG(4 00 *SECLVL)"
If I run this, I will get no difference in behavior.
$ /QOpenSys/usr/bin/system 'dspjob' | grep -E -A3 'LOG$' Message logging: LOG Level . . . . . . . . . . . . . . . . . . : 4 Severity . . . . . . . . . . . . . . . . . : 0 Text . . . . . . . . . . . . . . . . . . . : *NOLIST
What gives? Oh, duh! I forgot to add the
-i flag to run in the current
process. Silly me. Wait, even after adding
-i, it's still not working. womp,
What is going on? Well, if you understand the Unix process model, this does
starts to makes sense: we executed the
system command, causing BASH to start a
new process in which the
system command starts up (and if the
-i flag is
system spawns an additional job), calls
immediately exits. It sort of looks like this:
bash └── system -i ... -> CHGJOB bash └── system ... └── <spawned job> -> CHGJOB
In either case, this is quite pointless (even more so without
-i), as it still
hasn't affected our job. Luckily, the
CHGJOB command supports passing in a
job name, so we can use
getjobid to retrieve it:
/QOpenSys/usr/bin/system "CHGJOB JOB($(/QOpenSys/usr/bin/getjobid -s $$)) LOG(4 00 *SECLVL)"
What a pain in the butt! Of course this only works because
CHGJOB allows you
to specify a job name to affect. Other CL commands are not so lucky, like
Bash to the Rescue
Ok, so back to BASH. Because these new functions are builtins and not
commands, they execute in BASH itself, ie. the current job. This means when we
getjobid it gives you what you probably expected:
$ getjobid Process identifier 1574877 is 073846/QSECOFR/QP0ZSPWT $ getjobid Process identifier 1574877 is 073846/QSECOFR/QP0ZSPWT $ getjobid $$ Process identifier 1574877 is 073846/QSECOFR/QP0ZSPWT
In addition, we also have a
cl function, which behaves almost the same as
system, except it defaults to running in the current job, so no
needed. With that, we don't even need
getjobid for the above example:
cl "CHGJOB LOG(4 00 *SECLVL)"
And of course with builtins, it's finally possible to implement a
utility to change the library list of PASE jobs:
$ liblist -a kadler CPC2196: Library KADLER added to library list. $ liblist -d kadler CPC2197: Library KADLER removed from library list. $ liblist -c kadler CPC2198: Current library changed to KADLER. $ liblist QSYS SYS QSYS2 SYS QHLPSYS SYS QUSRSYS SYS QSHELL PRD KADLER CUR QGPL USR QTEMP USR QDEVELOP USR QBLDSYS USR
And because we're using the the
SQL service, we get the schema name for free so I figured why not add a
$ liblist -a LONGSCHEM CPC2196: Library LONGSCHEM added to library list. $ liblist -s QSYS SYS QSYS QSYS2 SYS QSYS2 QHLPSYS SYS QHLPSYS QUSRSYS SYS QUSRSYS QSHELL PRD QSHELL KADLER CUR KADLER LONGSCHEM USR longschemaname QGPL USR QGPL QTEMP USR QTEMP QDEVELOP USR QDEVELOP QBLDSYS USR QBLDSYS
Note that for compatibility with QSH liblist, the default output is kept the same.
Finally, ff that wasn't enough, if you ever forget what the command line arguments do, we have much better help text than the PASE or QSH equivalents 😁
$ cl --help cl: cl [-beEhiIkKnOpqsSv] COMMAND [ARG ...] Executes a CL command. Options: -i Run COMMAND in the current job (default) -S Run COMMAND in a spawned job -K Keep all spool files generated by COMMAND and the job log -k Keep all spool files generated by COMMAND -n Do not include the message identifier when writing the messages to standard error -p Only write the messages sent to the program's message queue by COMMAND to standard error -q Do not write messages generated by COMMAND to standard error -s Do not write spool files generated by COMMAND to standard output -v Write the complete command string to standard output before executing it -b Force binary mode for standard streams used by the CL command -e Copy PASE for i environment variables to ILE before running COMMAND -I Force CCSID conversion for standard input used by COMMAND -O Force CCSID conversion for standard output used by COMMAND -E Force CCSID conversion for standard error used by COMMAND Arguments: COMMAND The CL command to run. ARG One or more arguments to pass to the CL command
Questions, Caveats, and More
Checking for support
These builtins are available once you install bash 4.4-3. You can check if you
have the support and ensure you're using the builtin by using the
$ type liblist liblist is a shell builtin $ type cl cl is a shell builtin $ type getjobid getjobid is a shell builtin
which command will give you different results, since
which is an
external command and not a BASH builtin:
$ which getjobid /QOpenSys/usr/bin/getjobid
How do I use them?
Just call them like you would any other command. It's likely you're already
using BASH builtins and didn't even know it! (Things like
cd, and even
more used in scripting are also BASH builtins.)
When BASH has a builtin, it takes precedence over any external command found on
$ which getjobid /QOpenSys/usr/bin/getjobid $ type getjobid getjobid is a shell builtin
Why 'cl' and not 'system'?
liblist match the names their PASE/QSH counterparts,
we decided not to do the same with
cl — even though it has all the same
options. We did initially have it as
system, but there was concern that too
many existing PASE scripts relied on
system and depending on whether you ran a
ksh, etc you could get unexpected behavior.
You can always create a BASH alias for
system if you like. Run the following
or add it to one of BASH's startup
In addition, because we didn't have to worry about full compatibility with
system, we could change the default behavior to running in the current job,
which is probably what you want most of the time anyway. 🎉 This means no
-i is not needed (but supported for compatibility) and also a new
-S has been added to force
cl to spawn a new job.
This spawned job will run in a non-multithreaded job and without PASE loaded,
which can be useful for some commands.
How do I run the non-builtin version?
Since builtins have higher precedence over external commands, changing your
$PATH will have no effect. You need to either fully qualify the command or
disable the shell builtin.
# Fully qualify getjobid /QOpenSys/usr/bin/getjobid # Disable getjobid builtin for the current session enable -n getjobid