SHELL
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).
- http://iprodeveloper.com/application-development/introduction-qshell-part-1
- http://iprodeveloper.com/rpg-programming/introduction-qshell-part-2
- http://iprodeveloper.com/rpg-programming/introduction-qshell-part-3
- http://iprodeveloper.com/rpg-programming/introduction-qshell-part-4
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
- PASE GUI editor
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 needs your approval to pop up windows once
- 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??
- view ezgui_name.sh (click me) — GUI shell window control on IBM i
- view my_window (click me) — GUI window definition
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
- view ez_wrkactjob (click me) — GUI window definition
- 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→IBMi→IBMi→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.
- system wrksplf — produces the spool list above
- grep -i QPJOBLOG — filters only lines with QPJOBLOG
- awk ‘{print … }’ — prints individual catsplf commands
- 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
- view webfix.rpgle (click me) - RPG webfix decode GET/POST content
- view webfix (click me) - /QOpenSys/usr/bin/webfix PASE wrapper
1) myenv.sh
- view myenv.sh (click me) - sample 1) display webfix decode GET/POST content

2) myrun.sh
- view myrun.sh (click me) - sample 2) run webfix decode GET/POST content

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.
- view xmlrun.rpgle (click me) - RPG run XMLSERVICE
- view xmlrun (click me) - /QOpenSys/usr/bin/xmlrun PASE wrapper
1) xmlqry.sh
- view xmlqry.html (click me) - sample 1) html form query

- view xmlqry.sh (click me) - handle GET/POST query using XMLSERVICE

2) xmlcmd.sh
- view xmlcmd.html (click me) - sample 1) html form command

- view xmlcmd.sh (click me) - handle GET/POST command using XMLSERVICE
- view DemoXslt.xsl (click me) - XSL color me XML

3) xmlpgm.sh
- view xmlpgm.html (click me) - sample 1) html form program

- view xmlpgm.sh (click me) - handle GET/POST program using XMLSERVICE
- view DemoXslt.xsl (click me) - XSL color me XML

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