Shell

(click to open)

Quick Page Table of Contents

Scanning…

Fun with QSH, call qp2term and RPG …

This page is intended to unlock the IBM i mysteries about using QSH, QP2TERM, sh, ssh, etc., examples are provided, IBM i Operating System tricks exposed and interaction between these environments explained. The sections are intended to be read in order, as skills learned in each section lead to easy understanding of the more complex tasks.

  • Part 1 - QSH/QP2TERM (shells) — differences between QCMD, QSH, QP2TERM, shell pipes between environments
  • Part 2 - QSH/QP2TERM (parms) — shell parameters across QCMD, QSH, QP2TERM environments
  • Part 3 - QSH/QP2TERM (web) — everything learned can instantly be moved to IBM i web

If you know little about PASE see this link PASE In A Nutshell.

If you are simply looking for ksh93 auditing shell try this page ksh93.

Here is a great qshell set of articles from Scott Klement (but i personally never recommend QSH).

The quick of it …

  • Information below demonstrates the relationship between shells including starting form either qsh or qp2term (ssh). However, for ported scripts from AIX or Open Source, you are almost always better off using PASE shells (ssh, bash, sh, etc.) over QSH, as PASE shells are naturally ASCII based. Using PASE shells becomes increasingly important as you move to 2-tier operations Linux/Windows/Mac-2-IBM i over ssh or putty + ssh, etc., where often QSH scripts fail (sorry QSH lovers, the scripting world is really ASCII).
  • Special use case, if using ssh -X graphics, and seeing authorization issues (especially non-English systems), you may need to re-start your sshd manually
    ====
    IBM i
    ====
    endTCPSVR *SSHD
    /QOpenSys/QIBM/ProdData/SC1/OpenSSH/openssh-4.7p1/etc/sshd_config    (version varies release, PTF, etc.)
    X11Forwarding yes
    strTCPSVR *SSHD
    
    =====
    if you see connection rejected ...
    =====
    > ssh -X me@myibmi
    X11 connection rejected because of wrong authentication.
    X connection to localhost:10.0 broken (explicit kill or server shutdown).
    
    On client side (laptop) ...
    > xhost + myibmi
    
    ======
    I you see this error (especially non-English systems) ...
    ======
    ssh -X me@myibmi
    $ ssh -X me@myibmi
    me@myibmi's password: 
    /QOpenSys/usr/bin/X11/xauth: (stdin):1:  1356-373 unknown command "Usage:"
    /QOpenSys/usr/bin/X11/xauth: (stdin):2:  1356-373 unknown command "-n"
    
    edtf '/QOpenSys/QIBM/ProdData/SC1/OpenSSH/etc/sshd_config'
        # ibmpaseforilangid ESP
        # ibmpaseforicntryid ES
    un-comment/force ibmpaseforilangid/ibmpaseforicntryid to an invalid combination 
        ibmpaseforilangid ENU
        ibmpaseforicntryid ES
    this will force LANG=C and CCSID=819 (works most graphics)
    
    =========
    older versions sshd
    =========
    ... start from PASE (especially non-English systems) ...
    call qp2term
    export CCSID=819
    export LANG=C
    /usr/sbin/sshd&
    
  • PASE pty information (rarely needed) http://www-01.ibm.com/support/knowledgecenter/api/content/ssw_ibm_i_72/rzalf/rzalfpty.htm

Download examples

  • Attach:IBMiFunWithShells.pdf.zip — foil set related to this page
  • Attach:SHELL_use-1.0.3.zip — examples uses on this page (update 2013–03–08)
    • view easyMake (click me) — where everything goes in examples (included in zip)
    • This zip package also contains downloaded for convenience (completely untouched package binaries) …
      • PASE GUI editor http://sourceforge.net/projects/nedit/files/nedit-executable/5.5/nedit-5.5-AIX.tar.gz/download
      • PASE GUI scripting http://www.youngiprofessionals.com/wiki/index.php/EzWin/xgui10.tar.zip

Example of my favorite PASE utilities tricks (teaser) …

call qp2term
> cd /home/adc
> find . -type f | xargs grep -i auth

# above does ...
# find all regular files via recursive walk subdirs starting here ('.', this case is /home/adc),
# find utility feeds the input of xargs with a long list of file names,
# xargs then splits this list into sublists and calls 'grep -i auth' once for every sublist.
# grep looks -i case insensitive keywords 'auth' in each file (sublist) and
# only outputs files:keyword that match (try doing that by hand or by wrklnk ... no thanks)  

call qp2term
> system -i wrkactjob | grep -i php-cgi

# above does ...
# PASE system utility calls native commands like wrkactjob that support OUTPUT(*)
# wrkactjob feeds the input of grep a long list of jobs (same as green screen),
# grep looks -i case insensitive keywords 'php-cgi' in each job (sublist) and
# only outputs jobs that match (big time saver)

Part 1 - QSH/QP2TERM (shells)

QSH/QP2TERM (shells) vs. QCMD

QSH/QP2TERM provide basic interactive Unix shell environments that are essentially green screen for Unix operations. QSH/QP2TERM can run all manner of IBM/PASE commands/scripts, ILE/PASE programs (utilities), wander about file system, and generally control your machine similar to a traditional 5250 command line (QCMD).

There are fundamental differences between QSH/QP2TERM and QCMD:

  • No QCMD PF4 prompting. You must remember your parameters like all Unix geeks.
  • No QCMD style parameter passing. Only shell special utilities like system allow QCMD parameters.
call qp2term
> system "call MYLIB/MYPGM LAND('BEDROCK') BEFORE('FRED') TIME('16:53')"

No PF4 prompting??? No QCMD parameter passing??? Why are we still talking, kick Unix shell environments to the curb … read on, there are some nice things living in both QSH/QP2TERM shell environment and we RPG programmers can exploit many shell features.

Before you start …

IBM i arrives from manufacturing with a default machine QCCSID of 65535 (hex or binary), which is disaster for PASE<>ILE interaction. At issue, PASE runs ASCII and ILE runs EBCDIC, therefore interactions require a valid CCSID setting to allow conversion of string content between the two environments (not 65535).

  • DSPSYSVAL SYSVAL(QCCSID) … hopefully anything, except 65535 (hex, binary, no conversion, evil)

If dspsysval finds your machine set to 65535, please take action before continuing:

  • CHGSYSVAL SYSVAL(QCCSID) VALUE(37) — change entire machine
  • CHGUSRPRF USRPRF(ME) CCSID(37) — change your user profile

What happened IBM??? Architecturally, IBM i is the greatest business machine ever made, incredible story of longevity, a business machine so reliable that business programs created in 1970′s can still run world wide today (S/38). To wit, IBM i’s history of 65535 is simply a good world wide setting for years predating PASE arrival on the machine. IBM i leaves decisions of modern upgrades to you/operator, i suggest moving away from 65535 is needed in a modern world (most clients ASCII), but you can get around to changing your machines later by using CHGUSRPRF meantime.

QSH (ILE) vs. QP2TERM (PASE)

There are two primary green screen interactive shell environments on IBM i:

  • QSH (ILE sh) — born ILE, runs mostly ILE, taught how/when share command control with PASE sh
  • call qp2term (PASE sh) — born AIX, runs mostly PASE sh, taught how/when share command control with QSH

Shells are about pipes …

Shell environment interactions operate using interlocking pipes terminal<pipe>command, command<pipe>command, a very powerful idea forming the basis of all Unix style scripting languages. In fact, change pipe to socket and you get browser<socket>http-server, isn’t that interesting, same basic design now rules much of our world.

  • (0) STDIN/input pipe - human typing on keyboard … or … command STDIN reading STOUT of another command
  • (1) STOUT/output pipe - command display to user terminal … or … command chatting back to STDIN of another command
  • (2) STDERR/output pipe - command protesting error STDERR, but not mess up conversation between STDIN<>STDOUT
    • In beads picture below string represents connect pipes between each bead command, each command/bead running with input STDIN from bead in front and providing STDOUT output to be used by the next bead in on the string, until last bead has only original terminal to dump output (human sees last output)

QSH (ILE qsh) pipes

We can seen in QSH example “pipe | plumbing” is trick of choice for all Unix Geekdom.

  • (0) STDIN/input pipe - human input terminal ls /home/adc | grep zzentropy , press enter to end input and run
  • (1) STOUT/output pipe - command ls /home/adc outputs list of directory files to STDOUT
  • (0) STDIN/input pipe - command pipe | connects STDOUT of ls with STDIN of command grep zzentropy reads ls output as input
  • (1) STOUT/output pipe - command grep zzentropy looks for files named zzentropy and outputs all that match
  • (1) STOUT/output pipe - no additional pipe | connects, only output pipe available is original terminal, human sees output
    • (2) STDERR/output pipe - we had no interest STDERR, but if any command had error/complaint we would have seen on original terminal output pipe STDERR with no impact to STDIN<>STDOUT piping
    • Notice only *PGMs ran in this example (no PASE at all), ls -l /bin/ls /bin/grep shows only good old file/member /QSYS.LIB/QSHELL.LIB/LS.PGM and GREP.PGM (QSHELL/LS and QSHELL/GREP)

QP2TERM (PASE sh) pipes

We can seen same QP2TERM example “pipe | plumbing” is trick of choice for all Unix Geekdom.

  • Exact same piping as the QSH example.
    • Notice only PASE programs ran in this example, ls -l /QOpenSys/usr/bin/ls /QOpenSys/usr/bin/grep shows only PASE installed programs in /QOpenSys/QIBM/ProdData/OS400/PASE/bin/ls and grep.
    • Want to understand why PASE works? … try this link PASE In A Nutshell

QSH/QP2TERM (tricks)

What about ASCII<>EBCDIC??? What good is piping trick, when both sides speak different languages?

IBM Rochester developers have used pipe magic to auto-convert ASCII | EBCDIC, so most of the time you can pipe | connect most anything together. In this case we are filtering wrkactjob looking for specific criteria that we wish to see … but, there are tricks ILE/PASE you need to know …

Trick #1) PASE loader no ILE please …

In many examples this page it appears possible to execute ILE utilities in PASE (/bin/system), BUT your eyes are deceiving, PASE loader actually detects /bin/system is a symbolic link to ILE /QSYS.LIB/QSHELL.LIB/SYSTEM.PGM, which can not be executed in PASE (Permission denied). IBM i PASE loader has been taught to detect ILE situation for /usr/bin and looks for equivalent file name ‘SYSTEM.PGM’ in /QOpenSys/bin/system (PASE loader prepends /QOpenSys front of /bin/system), then executes PASE command equivalent. PASE loader append trick is tried for many links /bin, /usr/bin, etc., to allow much easier scripting in dual ILE/PASE environments (trust me, better of all evils).

  • We type or script ILE /bin/system (SYSTEM.PGM) <> PASE loader finds /QOpenSys/bin/system
  • We type or script ILE /bin/grep (GREP.PGM) <> PASE loader finds /QOpenSys/bin/grep
call qp2term
> /QSYS.LIB/QSHELL.LIB/SYSTEM.PGM
/QSYS.LIB/QSHELL.LIB/SYSTEM.PGM: Permission denied.

> ls -l /bin/system
lrwxrwxrwx    1 qsys     0                62 Oct 22 2007  /bin/system -> /QSYS.LIB/QSHELL.LIB/SYSTEM.PGM

> ls -l /QOpenSys/bin/system
lrwxrwxrwx    1 qsys     0                82 Mar 23 2010  /QOpenSys/bin/system -> ../../QIBM/ProdData/OS400/PASE/bin/system

This command actually ran /QOpenSys/bin/system due to PASE loader trick ...
> /bin/system dspsysval qccsid | grep -i qccsid
 QCCSID         65535                           65535                           Coded character set identifier

Why? — ILE QSH pre-dated PASE, so default AIX/Unix IFS geometry of /bin, /usr/bin, etc., was already occupied by ILE programs, therefore PASE graciously moved to /QOpenSys/bin, /QOpenSys/usr/bin, etc., and taught the PASE loader to understand the new default Unix geometry. Also, many parts of PASE actually need case sensitive file system /QOpenSys provides, for example PASE loader would never be able to load libc.a (c code) and/or libC.a (C++ code).

Warning — These PASE symbolic links MAY get corrupted when you play around with IFS SAV/RST or load alien AIX binaries, and things like java or ssh will stop working (ie. Apache http ADMIN port no longer working). In fact, well intended IBM i operators doing back-up/restores clobber these links so often, that IBM service starts to sound like a broken record please re-install PASE Option 33. So … cough … keep your SAV/RST activity away from IFS /bin, /usr/bin, /sbin, /lib, /usr/lib, /QOpenSys/bin, /QOpenSys/usr/bin, /QOpenSys/sbin, /QOpenSys/sbin/lib, /QOpenSys/sbin/usr/lib, etc.

Trick #2) PASE qsh wrapper script …

Permission denied??? Not for long … PASE added a qsh wrapper script to standard AIX script tools, so QSH tools can be used in the PASE environment. In the example below, notice qsh -c SYSTEM.PGM is pipe | connected to a PASE utility grep, best of all, because my user profile ADC is CCSID(37) the magic of piping did all the EBCDIC<›ASCII conversions. Hey, hey, hey, who needs QCMD?

ssh -X adc@lp0264d or call qp2term ...

> /QSYS.LIB/QSHELL.LIB/SYSTEM.PGM dsplibl
/QSYS.LIB/QSHELL.LIB/SYSTEM.PGM: Permission denied.

> qsh -c '/QSYS.LIB/QSHELL.LIB/SYSTEM.PGM dsplibl' | grep -i QS
    QSYS        SYS                    System Library
    QSYS2       SYS                    System Library for CPI's
    QSHELL      PRD

Trick #3) QSH hand off to PASE loader please …

Yes, you guessed QSH has also been taught PASE/ILE interaction, but QSH will hand off any non-ILE program to PASE loader.

  • Using PASE program easy from next example, we can see that QSH use a fully qualified path that clearly was not ILE program.
QSH
> cd /www/zendsvr/htdocs/Samples/SHELL_use
> easy fred flinstone
0 /www/zendsvr/htdocs/Samples/SHELL_use/easy -- program     (argv[0])
1 fred                                       -- parameter 1 (argv[1])
2 flinstone                                  -- parameter 2 (argv[2])
  • When we discuss scripting in the next section, we will see that QSH has also been taught to recognise PASE shebang script line 1 #!/QOpenSys/usr/bin/sh , and redirects to PASE auto-magically in scripting (IBM i sells you things you didn’t even know you needed).

Enough typing, try scripting

As you can see in the last example, many commands can be piped together across both environments, but who wants to type, much less remember all that stuff every time we want to preform wrkactjob filtering task? Well, necessity, or perhaps more accurate lazy is mother of invention, whereby Unix scripting was created to avoid repetitive tasks (programmers know it’s true).

Warning Windows editor issues (must read) …

Various Windows editors create files with new line sequence carriage-return+line-feed (CRLF or hex 0D0A), CRLF is unusable in PASE scripting (will not run). Files processed by PASE need to have their lines ended with a LF (hex 0A) character rather than with CRLF (hex 0D0A) characters. The use of a LF character at the end of lines is the norm for Unix/Linux (my good ssh -X GUI editor below). The use of CRLF at the end of lines is the norm for Windows (Uff Da). To fix Windows CRLF for PASE scripting use, try following CRLF stripping technique after FTP to IBM i (another use for IBM i scripting).

call qp2term
> tr -d '\015' < wrkactjob-filter1.sh > fixed-wrkactjob-filter1.sh

where:
- '<' - redirects IFS file as STDIN to command tr 
- '>' - redirects STDOUT to IFS file
- tr -d removes octal '\015' (decimal 13 or hex 0D) < wrkactjob-filter1.sh > fixed-wrkactjob-filter1.sh (creates a new file)

That CRLF Windows behaviour is really annoying, so often i simply edit directly on IBM i using ssh -X adc@lp0264d + GUI editor (nedit included in zip download). ssh -X is essentially like encrypted call qp2term on steroids, and allows me to use graphical editors on IBM i like nedit to create my wrkactjob-filter1.sh script (see Native IBM i GUI anyone?).

Remember PASE loader trick previous section??

  • line 1 in wrkactjob-filter1.sh is VERY important, so when you learn to script ALWAYS provide a shebang line 1 (#!) so you can run your script in nearly any environment. If you forget shebang (#!) you will enjoy all manner of random errors creeping into your scripts due to starting environmental differences (you have been warned). For my money, I ALWAYS start things in PASE shells, because … well, let’s face it … PASE/AIX has been doing the shell game for decades and qsh was only bolted on to IBM i as an afterthought (good work though).
  • Again, /bin/system is not running PASE sh example below because PASE shebang script line 1 #!/QOpenSys/usr/bin/sh caused PASE loader redirect auto-magically in scripting (/bin/system actually ran /QOpenSys/bin/system, etc.).
ssh -X adc@lp0264d

> cat wrkactjob-filter1.sh
#!/QOpenSys/usr/bin/sh                <--- line 1 in my script is shebang (#!) to let PASE loader/qsh know what shell to run  
/bin/system wrkactjob | \
/QOpenSys/usr/bin/grep -i php-cgi | \
/bin/grep TIMW | \
/QOpenSys/usr/bin/grep -i bci

> chmod +x wrkactjob-filter1.sh           <--- changed IFS authorization to allow PASE run of my saved my new script 
> wrkactjob-filter1.sh                    <--- ran my script ... no problem
   ZEND2        QTMHHTTP    797534   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797535   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797536   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797537   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797538   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797539   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797540   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797541   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797542   QTMHHTTP    BCI    2  25        .2                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797543   QTMHHTTP    BCI    2  25        .7                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797548   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797549   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797550   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797551   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797552   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797553   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797554   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797555   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797556   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    797557   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1

ILE (qsh)

And just to prove nothing up my sleeves, we will run our new command via QSH.

Remember QSH trick previous section??

  • QSH detected PASE shebang script line 1 #!/QOpenSys/usr/bin/sh caused redirect to PASE auto-magically (PASE /QOpenSys/usr/bin/sh used).

SBMJOB (qcmd)

And now just to show off, we will run our new command in batch, which will dump output to spool file (no terminal pipe in batch)

Remember QSH trick previous section??

  • Also in SBMJOB, QSH detected PASE shebang script line 1 #!/QOpenSys/usr/bin/sh caused redirect to PASE auto-magically (PASE /QOpenSys/usr/bin/sh used).
  • sbmjob
  • wrksplf
  • 5=Display

IBM i commands play shell OUTPUT(*)

We introduced shell scripting use of popular command wrkactjob, but why did this IBM i command work, while other IBM i commands do not?

As we learned, shells are about piping STDIN, STDOUT, STRERR. If we have terminal (qp2term, qsh, ssh, etc.), we see output pipe with our eyes, or we can script connect STDOUT<command>STDIN in a multi-command pipe. Also, if no visual terminal pipe is available, output pipe is directed to spool (SBMJOB example).

The OUTPUT(*) trick …

Various IBM i commands include OUTPUT(*), which, as you may have guessed, enables simple STDOUT pipe. Therefore, wrkactjob OUTPUT(*) default can fully participate in any environment, including Unix piping Geekdom.

call qp2term or QSH or ssh or ...

> system wrkactjob
 5761SS1 V6R1M0 080215                  Work with Active Jobs                                    2/25/13 11:37:37        Page    1
:
 Subsystem/Job  User        Number   User        Type Pool Pty     CPU   Int    Rsp  AuxIO   CPU%  Function       Status   Threads
 QBATCH         QSYS        552552   QSYS        SBS    2   0       3.4                  0     .0                  DEQW          2
 QCMN           QSYS        552555   QSYS        SBS    2   0        .6                  0     .0                  DEQW          2
   QACSOTP      QUSER       552579   QUSER       PJ     2  20        .0                  0     .0                  PSRW          1

> system wrkactjob | grep -i php-cgi
   ZEND2        QTMHHTTP    798311   QTMHHTTP    BCI    2  25        .1                  0     .0  PGM-php-cgi.bi  THDW          1
   ZEND2        QTMHHTTP    798322   QTMHHTTP    BCI    2  25       2.0                  0     .0  PGM-php-cgi.bi  THDW          1
   ZEND2        QTMHHTTP    798323   QTMHHTTP    BCI    2  25        .1                  0     .0  PGM-php-cgi.bi  THDW          1
   ZEND2        QTMHHTTP    798324   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1

PASE product example utility db2

We have covered the basics above, so here is a production mapping script shipped with PASE.

call qp2term or ssh -X adc@lp0264d ...

/usr/bin/db2 utility is an IBM ILE program ...
> ls -l /usr/bin/db2
lrwxrwxrwx    1 qsys     0                44 Oct 22 2007  /usr/bin/db2 -> /QSYS.LIB/QZDFMDB2.PGM


/QOpenSys/usr/bin/db2 is an IBM PASE wrapper script ...
> which db2
/QOpenSys/usr/bin/db2

Here is the source (minus legal/comments) ... #!/QOpenSys/usr/bin/ksh assures run PASE always
> cat /QOpenSys/usr/bin/db2
#!/QOpenSys/usr/bin/ksh
# map base name "qsh_inout" to "qsh" (just run the interpreter)
basename=${0##*/}
if [[ "$basename" = qsh_inout ]] ; then
        basename=qsh
fi
args=''
for temp ; do
        args="$args'"
        # double embedded quotes halved by CL CALL
        while [[ "$temp" = *\'* ]] ; do
                args="$args${temp%%\'*}''"
                temp="${temp#*\'}"
        done
        args="$args$temp' "
        shift
done
# Copy environment variables, call utility in this process,
# do not process OS/400 messages or spooled output files
exec /QOpenSys/usr/bin/system -eiqs "CALL QSYS/QP0ZCALL ('/usr/bin/$basename' $args)"
> 

Example usage db2 utility …

> db2 'select * from db2.animals'

ID          BREED                            NAME             WEIGHT   
----------- -------------------------------- ---------------- ---------
          0 cat                              Pook                  3.20
          1 dog                              Peaches              12.30
          2 horse                            Smarty              350.00
          3 gold fish                        Bubbles               0.10
          4 budgerigar                       Gizmo                 0.20
          5 goat                             Rickety Ride          9.70
          6 llama                            Sweater             150.00

  7 RECORD(S) SELECTED.

> db2 'select * from db2.animals' | grep -i horse
          2 horse                            Smarty              350.00
> 

Native IBM i GUI anyone??

This section is optional, but i use ssh -X adc@lp0264d and PASE GUI editor nedit every day, so i am including section on native IBM i X graphics to round out your IBM i scripting super geek skills (even super geeks use graphical editors these days).

I am using ssh -X adc@lp0264d, which allows native IBM i graphics, so let’s make shell scripting IBM i PASE pop up a GUI windows using ezwindow download on this site link GUI. All the screen copy graphics you see below came from my IBM i (lp0264d), i am simply using my Ubuntu machine windows like any other application running on the laptop. (Yep, Linux/Windows/Mac experts keep saying no GUI on IBM i … cough … not polite to argue with majority views, so i simply continue to use IBM i X GUI/graphics every day).

IBM i PASE X/GUI applications work best local networks, so if you live in New York and your IBM i is in Arizona using ssh -X will become really slow.

Ranger’s GUI editor of choice on IBM i …

For your convenience, i included a copy of tar/zip executable packages nedit and ezwindow in this page download zip. These files have not been touched in any way from the download, just handy to have it all in one zip file for this demonstration (see top of page).

  • Both e and nedit are same on my machine … i was too lazy to type nedit all the time and switched to using e (ok, really lazy)
  • view easyMake top of page to see where executable files are suppose to go (or 4 below)
    • /QOpenSys/usr/bin/nedit
    • /QOpenSys/usr/bin/e
    • /QOpenSys/usr/bin/ezwindow
ssh -X adc@lp0264d
> nedit wrkactjob-filter1.sh &            <--- brings up graphical editor on my laptop using PASE X windowing (really IBM i doing this)

Problems??

1) check DISPLAY variable set by ssh -X 
on IBM i ...
> echo $DISPLAY
localhost:10.0               <---this is the secure encrypted tunnel
                                 back to your laptop running ssh -X 

2) you also need to enable xhost on your laptop
on laptop running ssh -X ... 
> xhost + lp0264d            <---use your IBM i TCP name (of course)

3) you may need to use ssh -Y 
ssh -Y adc@lp0264d           <---long story, but -Y means original security model (argh)

4) easyMake puts everything correct directories,
   but here is cut/paste of info from zip download
echo "nedit download http://sourceforge.net/projects/nedit/files/nedit-executable/5.5/nedit-5.5-AIX.tar.gz/download ..."
rm -R nedit-5.5-AIX-4.3
tar -xf nedit-5.5-AIX.tar
cp nedit-5.5-AIX-4.3/nedit /QOpenSys/usr/bin/nedit
chmod 0755 /QOpenSys/usr/bin/nedit
cp nedit-5.5-AIX-4.3/nedit /QOpenSys/usr/bin/e
chmod 0755 /QOpenSys/usr/bin/e
echo "ezwindow download (http://www.youngiprofessionals.com/wiki/index.php/EzWin/xgui10.zip) ..."
rm -R xgui10
unzip xgui10.zip
cp xgui10/ezwindow /QOpenSys/usr/bin/ezwindow
chmod 0755 /QOpenSys/usr/bin/ezwindow

Configuration -X graphics …

  • on my IBM i (lp0264d) …
    • i enabled X11Forwarding yes in etc/sshd_config on my IBM i, before starting strtcpsvr server(*SSHD), this enables -X graphics to my laptop SSHSetup.
  • laptops ssh -X adc@lp0264d (-X graphics on IBM i)
    • … laptop needs your approval to pop up windows once >xhost + lp0264d (on laptop)
  • laptop, laptop, tablet (duck, duck, goose) …
    • Linux? my laptop with secure/encrypted ssh -X (Ubunutu laptop) …
    • Mac? laptop with secure/encrypted ssh -X (Apple laptop) …
    • Windows? laptop (± opinion) … needs X package … needs secure/encrypted ssh -X …
      • Use cygwin startx and ssh package (better) … ClientPgms
      • Or try vnc (slower, clunky, insecure) … 5799PTLPRPQ

Just for fun, GUI windows on IBM i (optional) …

How about something simple to start??

ssh -X adc@lp0264d
> e ezgui_name.sh&           <---included nedit in package (see easyMake)
> chmod 0755 ezgui_name.sh
> ezgui_name.sh              <---pop up window now  (all IBM i X here)

Problems?? see start of this section

GUI wrkactjob IBM i (optional) …

How about a native GUI version of WRKACTJOB??

  • view ezgui_wrkactjob.sh (click me) — GUI shell WRKACTJOB control on IBM i
  • Notes:
    • suggest using *SECOFR profile (like my adc@lp0264d) or DSPJOB functions may not have authority to present second info panel data
    • you may have to play around ezgui_wrkactjob.sh DSPJOB filtering to handle mismatched unescaped characters in data operations like *JOBLOG that may cause big yellow GUI error panel to appear (.,’,”,;,comma) … good shell geek practice anyway (hey this was a 10 minute script)
ssh -X adc@lp0264d
> e ezgui_wrkactjob.sh &           <---included nedit in package (see easyMake)
> chmod 0755 ezgui_wrkactjob.sh
> ezgui_wrkactjob.sh               <---pop up window now (all IBM i X here)

Problems?? see start of this section

ssh -Y graphics linux→IBMiIBMi→linux??

One of the cool tricks using -Y is forwarding X11 (graphics) across many “hops”. This can help you do graphical work on a machine deep in your enterprise from laptop (Linux or Mac of course … ok … also Windows with X package). Hint: Yes interesting concept for those quick thinking firewall annoyed folks (but you didn’t hear it for me).

The -Y flag "Enables trusted X11 forwarding."
> ssh -Y myibmi
$ ssh -Y mylinux
> firefox&  <--- up pops firefox browser
                 BUT not all linux gui apps (gnome/kde) 

This also works with multiple "hops" ... if each sshd_config on each machine enables X11Forwarding yes
Starting on my linux machine ...
ssh -Y lp0264d.rch.stglabs.ibm.com      .... hop to my ibm i V6
-> ssh -Y lp0364d.rch.stglabs.ibm.com    ... hop to my ibm i V7
--> ssh -Y adc@9.10.111.44               ... hop back to my linux machine (see below)
---> firefox&                            ... up pops firefox 


===============
example:
================
[9.10.111.44] - linux (red hat 64) 
[lp0264d    ] - IBM i (V6)

====================== 
9.10.111.44 (linux)
======================
$ sudo gedit /etc/ssh/sshd_config
X11Forwarding yes
$ sudo service sshd start
Starting sshd:                                             [  OK  ]
$ ps -ef | grep sshd
root      8621     1  1 15:12 ?        00:00:00 /usr/sbin/sshd
adc       8640 11276  0 15:12 pts/38   00:00:00 grep sshd

====================== 
lp0264d (IBM i)
======================
[lp0264d] e /QOpenSys/QIBM/ProdData/SC1/OpenSSH/openssh-3.8.1p1/etc/sshd_config &
X11Forwarding yes
Note: edit file any way, but enable X11Forwarding yes

====================
linux->IBM i->linux (with -Y graphics forward)
====================
[9.10.111.44]> ssh -Y adc@lp0264d
adc@lp0264d's password: 
Welcome to LP0264D

[lp0264d]$ ssh -Y adc@9.10.111.44
adc@9.10.111.44's password: 
Last login: Wed Aug 21 15:08:41 2013 from lp0264d.rch.stglabs.ibm.com
====> Welcome to the IBM Open Client <====

[9.10.111.44]> firefox&


Impressed yet??

For IBM i geeks this demonstration of full power shell environments is the beginning of a whole way of thinking, but if you are still sceptical just wait until we start covering RPG exploitation of shell pipe magic.

Part 2 - QSH/QP2TERM (parms)

Starting with QCMD …

Predictably, most IBM i folks ask how do we pass parameters to RPG/CL programs using shells (QSH, call qp2term, etc.)??? As we have seen in previous examples, shells are not designed to emulate QCMD style parameter passing environments, instead shells are better utilised under pipe chains STDIN, STOUT, STRERR with IBM i commands using OUTPUT(*), such as wrkactjob (last example). However, there are shell tricks that join shells with the world of QCMD.

  • shell utility system
    • system "call MYLIB/MYPGM LAND('BEDROCK') BEFORE('FRED') TIME('16:53')"
  • shell exec program convention argv
    • int main(int argc, char *argv[]) { return 0; }

Some like it hot, others not …

Many IBM i ILE/PASE geeks find full power shell programming environments cool (easy.c, easyrpg.rpgle), other folks find only a headache. If in headache crowd, perhaps stick with command line QSH/QP2TERM scripting using system.

High level scripting (geekdom) …

The system command level utility can be used to very powerful effect on IBM i. Very useful for command line and scripting processing without additional ILE programming (easy.c, easyrpg.rpgle). In essence, most things you can do from QCMD, can also be done from shell utility system.

Geek out shell demonstration of printing QPJOBLOG(s), using QCMD style QSH CMD(‘action’) …

call qp2term or qsh or ssh ...

> system wrksplf
 File       User       Queue      User Data  Sts  Pages  Page Copy Form Type  Pty Date     Time       Nbr  Job        Number
 QPJOBLOG   ADC        PRT01      QPADEV000G RDY      2          1 *STD        5  02/23/13 01:19:00     1  QPADEV000G 798016

 $1         $2         $3         $4         $5      $6        $7    $8        $9 $10      $11        $12  $13        $14

> ls -l /usr/bin/catsplf 
lrwxrwxrwx    1 qsys     0                64 Oct 22 2007  /usr/bin/catsplf -> /QSYS.LIB/QSHELL.LIB/CATSPLF.PGM

The wrksplf example above demonstrates space separated data convention that we will exploit in the long string of piped commands below. However, if you look closely at the space separated data wrksplf you will notice not all lines have same count geometry (nuts), but for this command line example we will assume QPJOBLOG lines will have $1 through $14 available for awk program to pick out fields and create catsplf commands.

  1. system wrksplf — produces the spool list above
  2. grep -i QPJOBLOG — filters only lines with QPJOBLOG
  3. awk ‘{print … }’ — prints individual catsplf commands
  4. sh — executes printed catsplf commands
system wrksplf | grep -i QPJOBLOG | awk '{print "system -i \"qsh cmd('\''catsplf -j "$14"/"$2"/"$13" "$1" "$12"'\'')\" "}' | sh

If we wish to see what awk is producing before actually executing just remove | sh ...

> system wrksplf | grep -i QPJOBLOG | awk '{print "system -i \"qsh cmd('\''catsplf -j "$14"/"$2"/"$13" "$1" "$12"'\'')\" "}'
system -i "qsh cmd('catsplf -j 798016/ADC/QPADEV000G QPJOBLOG 1')" 
system -i "qsh cmd('catsplf -j 797888/ADC/QPADEV0002 QPJOBLOG 1')" 
system -i "qsh cmd('catsplf -j 798309/ADC/QPADEV0002 QPJOBLOG 3')" 

We can also make use of qsh, qsh_inout, qsh_out to extend out PASE shell capabilities. The qsh and qsh_inout commands perform encoding conversion between ASCII and EBCDIC for standard input, standard output, and standard error. The qsh_out command performs the encoding conversion only for standard output and standard error.

The following example assumes we are using a *SECOFR profile and wish to DSPJOBLOG of running java jobs on the IBM i system. Using our accumulated skills from previous examples makes this task a 2-minnute job, instead of wasted time snooping with wrkactjob … and … best part we can filter for anything we want find using grep. So, now you are a real Unix command line geek (welcome all)!

call qp2term or ssh -X adc@lp0264d ...

Note the use of '>' to redirect STOUT to file > test.txt ...

> ps -ef | grep -i java | awk '{print "qsh_out -c '\''/usr/bin/getjobid "$2"'\''"}' | sh | awk '{print "qsh_out -c \"system -i '\''dspjoblog job("$5")'\''\""}' | sh > test.txt
> head test.txt 
  5761SS1 V6R1M0 080215                        Display Job Log                        LP0264D  02/28/13 14:40:46          Page    1
   Job name . . . . . . . . . . :   QSRVMON         User  . . . . . . :   QSYS         Number . . . . . . . . . . . :   552621
   Job description  . . . . . . :   QSRVJOB         Library . . . . . :   QSYS
 MSGID      TYPE                    SEV  DATE      TIME             FROM PGM     LIBRARY     INST     TO PGM      LIBRARY     INST
 CPF1124    Information             00   08/05/12  20:11:07.931757  QWTPIIPP     QSYS        04C0     *EXT                    *N
                                      From user . . . . . . . . . :   QSECOFR
                                      Thread  . . . . :   00000002
                                      Message . . . . :   Job 552621/QSYS/QSRVMON started on 08/05/12 at 20:11:06 in
                                        subsystem QSYSWRK in QSYS. Job entered system on 08/05/12 at 20:11:06.
 JVAB302    Diagnostic              10   08/05/12  20:11:08.898059  QJVAJVMXIF   QSYS        *STMT    QJVAJVMXIF  QSYS        *STMT
> tail test.txt
                                      From procedure  . . . . . . :   sendMessage__10QjvaJvmXifFPcPviT1
                                      Statement . . . . . . . . . :   10
                                      To module . . . . . . . . . :   QJVAJVMXIF
                                      To procedure  . . . . . . . :   check_J9_Envvar__10QjvaJvmXifFv
                                      Statement . . . . . . . . . :   129
                                      Thread  . . . . :   000006F4
                                      Message . . . . :   Java Virtual Machine is IBM Technology for Java.
                                        PID(195349)
                                      Cause . . . . . :   JAVA_HOME environment variable is
                                        /QOpenSys/QIBM/ProdData/JavaVM/jdk50/32bit
> 


Again, to see command awk is building leave off | sh ...
> ps -ef | grep -i java | awk '{print "qsh_out -c '\''/usr/bin/getjobid "$2"'\''"}' | sh | awk '{print "qsh_out -c \"system -i '\''dspjoblog job("$5")'\''\""}' 
qsh_out -c "system -i 'dspjoblog job(552621/QSYS/QSRVMON)'"
:
qsh_out -c "system -i 'dspjoblog job(800268/QSECOFR/QP0ZSPWP)'"


Just keep chopping off '|' to understand the whole script line ...

> ps -ef | grep -i java | awk '{print "qsh_out -c '\''/usr/bin/getjobid "$2"'\''"}' 
qsh_out -c '/usr/bin/getjobid 20'
:
qsh_out -c '/usr/bin/getjobid 195349'

> ps -ef | grep -i java 
 qsecofr     20     17   0   Aug 05      - 20:57 /QOpenSys/QIBM/ProdData/JavaVM/jdk50/32bit/jre/bin/jvmStartPase 703 
:
     adc 195349 195348   0 09:00:07  pts/1  0:02 /QOpenSys/QIBM/ProdData/JavaVM/jdk50/32bit/jre/bin/jvmStartPase 1637 

My OWN shell utilities (c,rpg)

An example is often the easiest way to understand, so we will offer an easy command for each environment that demonstrates.

my PASE shell program easy.c …

First rule of shell programming, commands are delimited by spaces …

call qp2term or qsh or ssh or ...
> ls   -l   /home/adc
  $0   $1   $2  
  where:               (argc=3)    
    $0 - program name  (argv[0])
    $1 - parameter 1   (argv[1])
    $2 - parameter 2   (argv[2])

PASE utilities follow easy program general scheme (± fancy parameter coding) …

ssh -X adc@lp0264d or call qp2term ...

----------------
easy with shell parameters (argv[]) 
----------------
> easy i am really glad "to finally understand" shell programming | awk '{print "-"$1"-"$2"-"$3"-"$4}'
-00000-easy--
-00001-i--
-00002-am--
-00003-really--
-00004-glad--
-00005-to-finally-understand
-00006-shell--
-00007-programming--

----------------
using easy in a pipe script
----------------
> pwd
/www/zendsvr/htdocs/Samples/SHELL_use
> ls | easy -pipe
00000 easy
00001 -pipe
00000 core
00001 easy
00002 easy.c
00003 easyRPG.rpgle
00004 ftpcompile.sh

Command also available for QSH use …

my ILE shell program EASYRPG.PGM …

call qp2term

EASYRPG.PGM make a symbolic link for easy command processing ...
> ln -sf /qsys.lib/qgpl.lib/EASYRPG.PGM /usr/bin/easyrpg

EASYRPG.PGM owner (ADC) *RWX , group *NONE, public *RX ...
> chmod 0705 /qsys.lib/qgpl.lib/EASYRPG.PGM

Command available for QSH use …

Remember PASE qsh trick …

New /usr/bin/easyrpg will NOT run directly in PASE environment (permission denied), but we can use the PASE qsh -c script trick we learned in previous section to allow our new easyrpg utility to play ball with PASE scripting, best of all, because my user profile ADC is CCSID(37) the magic of piping did all the EBCDIC<>ASCII conversions. Hey, hey, hey, who needs QCMD?

ssh -X adc@lp0264d or call qp2term ...

> ls -l /usr/bin/easyrpg 
lrwxrwxrwx    1 adc      0                60 Feb 26 14:37 /usr/bin/easyrpg -> /qsys.lib/qgpl.lib/EASYRPG.PGM

> /usr/bin/easyrpg fred flinstone
/usr/bin/easyrpg: Permission denied.

> qsh -c '/usr/bin/easyrpg i am really glad "to finally understand" shell programming' | awk '{print "-"$1"-"$2"-"$3"-"$4}'
-1-i--
-2-am--
-3-really--
-4-glad--
-5-to-finally-understand
-6-shell--
-7-programming--
> 

-- or --

> system -i 'call pgm(qgpl/easyrpg) parm('\''i'\'' '\''am'\'' '\''really'\'' '\''glad'\'' '\''to finally understand'\'' '\''shell'\'' '\''programming'\'')' |  awk '{print "-"$1"-"$2"-"$3"-"$4}'
-1-i--
-2-am--
-3-really--
-4-glad--
-5-to-finally-understand
-6-shell--
-7-programming--

Finally we steal a trick from production PASE (remember db2 utility) …

call qp2term or ssh adc@lp0264d ...

No easyrpg in PASE shell path ...
> which easyrpg
easyrpg: Command not found.

No easyrpg in PASE /QOpenSys/usr/bin ...
> ls -l /QOpenSys/usr/bin/easyrpg
/QOpenSys/usr/bin/easyrpg not found

So, we create wrapper script link (just like utility db2) ...
> cp /www/zendsvr/htdocs/Samples/SHELL_use/easyrpg /QOpenSys/usr/bin/easyrpg
> chmod 0755 /QOpenSys/usr/bin/easyrpg

Eureka! Now we have our own PASE utility (really RPG) ...
> which easyrpg
/QOpenSys/usr/bin/easyrpg

And works just fine ...
> easyrpg i am really glad "to finally understand" shell programming | awk '{print "-"$1"-"$2"-"$3"-"$4}'
-1-i--
-2-am--
-3-really--
-4-glad--
-5-to-finally-understand
-6-shell--
-7-programming--

Our wrapper script (just like db2 utility) ...
> cat /QOpenSys/usr/bin/easyrpg
#!/QOpenSys/usr/bin/ksh
# map base name "qsh_inout" to "qsh" (just run the interpreter)
basename=${0##*/}
if [[ "$basename" = qsh_inout ]] ; then
        basename=qsh
fi
args=''
for temp ; do
        args="$args'"
        # double embedded quotes halved by CL CALL
        while [[ "$temp" = *\'* ]] ; do
                args="$args${temp%%\'*}''"
                temp="${temp#*\'}"
        done
        args="$args$temp' "
        shift
done
# Copy environment variables, call utility in this process,
# do not process OS/400 messages or spooled output files
exec /QOpenSys/usr/bin/system -eiqs "CALL QSYS/QP0ZCALL ('/usr/bin/$basename' $args)"

>

Impressed yet??

For IBM i geeks this demonstration of full power shell environments is the beginning of a whole way of thinking, but if you are still sceptical how about move everything just learned onto the web … you heard right, i said move everything onto the web (± authorizations).

Part 3 - QSH/QP2TERM (web)

PASE sh CGI (same skills)

Hey, everything you just learned about shells is directly transferable to web environment.

PASE CGI trick change httpd.conf to run shells (any instance) …

IBM i Apache HTTP server has been trained to run PASE CGI(s) form directories starting with /QOpenSys. This is the only trick you have to learn to get this whole thing on the web.

call qp2term or ssh -X adc@lp0264d ...

Note your httpd.conf may be EBCDIC, so is so, use EDTF ...
> e /myasp2/www/zend2/conf/httpd.conf &

# Yep, dspsysval QCCSID, 65535 protection required ...
# PASE<>ILE string conversion requires a valid CCSID
# invalid QCCSID 65535 (hex, binary, evil)
DefaultFsCCSID 37
CGIJobCCSID 37

# sh cgi wrapper program
ScriptAlias /sh-bin/ /QOpenSys/sh-bin/
AddType application/x-httpd-sh .sh
Action application/x-httpd-sh /sh-bin/sh-cgi
<Directory /QOpenSys/sh-bin>
Options +ExecCGI
order allow,deny
allow from all
</Directory>

# sh applications (.sh)
Alias /sh-htdocs /QOpenSys/sh-bin/sh-htdocs
<Location /sh-htdocs>
Order deny,allow
Allow from all
</Location>

Need a small script for routing …

call qp2term or ssh -X adc@lp0264d ...

> mkdir /QOpenSys/sh-bin
> e /QOpenSys/sh-bin/sh-cgi & (see above)

Our 1st web script …

call qp2term or ssh -X adc@lp0264d ...

> mkdir -p /QOpenSys/sh-bin/sh-htdocs
> e /QOpenSys/sh-bin/sh-htdocs/hello.sh & (see above)

VERY IMPORTANT allow web to execute our scripts ... 
> chmod -R 0755 /QOpenSys/sh-bin

We are done folks, restart your Apache instance (only 1st time with hello.sh) ...
> system -i 'endtcpsvr server(*HTTP) instance(ZEND2)'
TCP1A17: HTTP server ended.
> system -i 'strtcpsvr server(*HTTP) instance(ZEND2)'
TCP1A0F: HTTP server starting.

Browser address (my machine) ...
http://lp0264d/sh-htdocs/hello.sh
Output:
Hello, world from sh!

Our samples on web …

e /QOpenSys/sh-bin/sh-htdocs/easyrpg.sh & (see above)

VERY IMPORTANT allow web to execute our scripts ... 
> chmod -R 0755 /QOpenSys/sh-bin

... and our database is going read on the web ...
> chmod -R 0755 /qsys.lib/db2.lib
> chmod -R 0755 /qsys.lib/db2.lib/ANIM*

Browser address (my machine) ...
http://lp0264d/sh-htdocs/easyrpg.sh
Output:
call pgm(qgpl/easyrpg)
-1-i--
-2-am--
-3-really--
-4-glad--
-5-to-finally-understand
-6-shell--
-7-programming--
easyrpg (/QOpenSys/usr/bin/easyrpg)
-1-i--
-2-am--
-3-really--
-4-glad--
-5-to-finally-understand
-6-shell--
-7-programming--
db2 (/QOpenSys/usr/bin/db2)
select * from db2.animals

ID          BREED                            NAME             WEIGHT   
----------- -------------------------------- ---------------- ---------
          0 cat                              Pook                  3.20
          1 dog                              Peaches              12.30
          2 horse                            Smarty              350.00
          3 gold fish                        Bubbles               0.10
          4 budgerigar                       Gizmo                 0.20
          5 goat                             Rickety Ride          9.70
          6 llama                            Sweater             150.00

  7 RECORD(S) SELECTED.
wrkactjob (like wrkactjob-filter1.sh)
   ZEND2        QTMHHTTP    801567   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801568   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801569   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801570   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801571   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801572   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801573   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801574   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801575   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801576   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801586   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801587   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801588   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801589   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801590   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801591   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1
   ZEND2        QTMHHTTP    801592   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-php-cgi.bi  TIMW          1

Advanced web parms …

Let us move to more interesting web material by creating a mini web language for IBM i using ksh.

web parms …

Our Apache HTTP web service has an agreement with REST capable clients (browsers), a simple trick whereby all GET/POST data will arrive escape encoded to avoid nasty translations as data wanders about the web TCP.

http://lp0264d/sh-htdocs/myenv.sh?action='swim in the lake'@goal='to cool off'@later='have lunch on shore'
-- becomes --
action=%27swim%20in%20the%20lake%27@goal=%27to%20cool%20off%27@later=%27have%20lunch%20on%20shore%27

Good for web, bad for shell scripts, so we will create a simple RPG decoder webfix.rpgle by hacking into IBM i’s Apache core engine BNDSRVPGM(QHTTPSVR/QZSRCORE). We need a function similar to Apache documentation for ap_unescape_url … mmm … looks like ebcdic_unescape_url may do the trick with only a little more decode monkey business.

> system -i "dspsrvpgm srvpgm(qhttpsvr/qzsrcore) detail(*PROCEXP)" | grep -i unescape
 ap_unescape_url                                                            *NO
 ebcdic_unescape_url                                                        *NO
 ap_unescape_url_keep2f                                                     *NO

1) myenv.sh

2) myrun.sh

Advanced web xmlservice …

If you are familiar with PHP, you are probably aware of the PHP Toolkit, which uses RPG program XMLSERVICE hosted on this site. Basically XMLSERVICE can web call anything on the IBM i system (± authorizations), so for our second advanced script function we will make a ksh toolkit interface to XMLSERVICE xmlrun.rpgle.

1) xmlqry.sh

2) xmlcmd.sh

3) xmlpgm.sh

Common questions

eliminate CPC2206 messages (spool)

‘Unix/PASE/QSH’ action for noisy CPC2206 STDERR (2) is redirect to /dev/null …

system 'WRKACTJOB' 2> /dev/null

db2 utility issues

PASE shells call ILE programs, perhaps where IBM i beauty meets eye of the beholder (ssh or call qp2term) …

Q: What is happening here (ssh or call qp2term)?????
qp2term> db2 'select * from db2.animals'
         /usr/bin/db2: Permission denied

Q: What's the best approach for using the db2 command from pase (from qp2term or ssh )?
A: qp2term> system "CALL PGM(QZDFMDB2) PARM('select * from db2.animals')"
    ID          BREED                            NAME             WEIGHT   
    ----------- -------------------------------- ---------------- ---------

Q: Why system "CALL PGM(QZDFMDB2)"?
A: Utility 'db2' is actually a ILE program, therefore CALL PGM(QZDFMDB2) PARM('select * from db2.animals')
   qp2term> ls -l /usr/bin/db2
            lrwxrwxrwx    1 qsys     0                44 Oct 22 2007  /usr/bin/db2 -> /QSYS.LIB/QZDFMDB2.PGM

Q: Ahh, so utility db2 works from QSH, but not PASE?
A: Yes. QSH is an ILE shell, therefore runs ILE programs (QZDFMDB2.PGM)
   QSH> db2 'select * from db2.animals'
    ID          BREED                            NAME             WEIGHT   
    ----------- -------------------------------- ---------------- ---------

Q: Can i make a PASE utility to emulate QSH 'db2' for qp2term and ssh?
A: Yes (shh don't tell PASE guys)
   qp2term> cp /QOpenSys/usr/bin/ipcs /QOpenSys/usr/bin/db2 
   qp2term> chmod +x /QOpenSys/usr/bin/db2
   qp2term> db2 'select * from db2.animals'
    ID          BREED                            NAME             WEIGHT   
    ----------- -------------------------------- ---------------- ---------

Author(s)

Tony “Ranger” Cairns - IBM i PHP / PASE