-   Linux - Software (
-   -   how do i use s3270/x3270 for scripting (

doomed9 11-05-2009 09:11 AM

how do i use s3270/x3270 for scripting
I'm trying to write a script which will (upon completion), navigate through records maintained on an IBM mainframe using a tn3270 terminal, and scrape said records into html files for later manipulation.

I've read


The latter states:

Commands are emulator actions; the syntax is the same as for the right-hand side of an Xt translation table entry (an x3270 or c3270 keymap). Unlike translation tables, action names are case-insensitive, can be uniquely abbreviated, and the parentheses may be omitted if there are no parameters. Any input line that begins with # or ! is treaded as a comment and will be ignored.

By that definition, the following should work:


connect( \
ascii() \
string(command1) \
enter() \
ascii() \
enter() \
string(command2) \
ascii() \
pf(3) \

However, when i call the above using the script() function in s3270, the script prints to stdout, but the actions are not executed as expected.

For example:


(NOTICE: I've shortened the script for example's sake)
$ s3270

L U U N N 4 24 80 0 0 0x0 -

Expected output would've been (for starters) the first character of the status string changing to U (as the keyboard should unlock when i am connected), and the initial screen printed in ascii, a command sent, and the resulting screen printed in ascii as well.

I'm not sure what i am doing wrong. Can someone give me an example script that works? Something simple that depicts how i can use something like bash, perl, or python to send commands to this application and navigate through screens.

Thanks in advance

doomed9 11-05-2009 07:12 PM

So, i worked out how to do this in bash; though, i don't like the result.


date=$(date +"%Y%m%d%H%M%S")
x3270if "connect("
x3270if "printtext(html,file,$file_path/myhost-$date.html)"
x3270if "string(command1)"
x3270if "enter"
x3270if "printtext(html,file,$file_path/myhost-$date.html)"
x3270if "enter"
x3270if "string(command2)"
x3270if "enter"

This is a bash script that, if called from within s3270, will navigate to the application login page and create html files of each page along the way.

while x3270if is nice, i reckon i expected a simpler solution...something easier to use with a language's built-in functionality.

What would i do with perl? Hopefully not make a call to system() each time i want to input data. Is there a way to treat the terminal connection as a file handle and just send commands to it via print()?

chrism01 11-06-2009 01:18 AM

If you're keen on doing this in Perl, ask the gurus over at

doomed9 11-07-2009 04:55 PM


Thank you for the excellent referral. I was on the right track to my answer in a few minutes...

Using perl's IPC::Run module, i was able to pipe commands directly to the s3270 subprocess. Thus, the below is an example of x3270's peer script facility:



my @s3270 = s3270;

use IPC::Run qw( start pump finish timeout );
      # Incrementally read from / write to scalars.
      # $in is drained as it is fed to s3270's stdin,
      # $out accumulates s3270's stdout
      # $err accumulates s3270's stderr
      # $h is for "harness".
      my $h = start \@s3270, \$in, \$out, \$err, timeout( 10 );

      $in .= "connect(\n";
      $in .= "ascii\n";

      $in .= "quit";
      finish $h or die "s3270 returned $?";

      warn $err if $err;
      print $out;        ## All of cat's output

hope this helps any googlers interested in scripting with s3270.

Chris, Thanks again :)

ffabreti 07-05-2010 08:11 PM

X3270 Script Example
I had similar problem and, although it's an old topic, I'd like to share a bourne shell script that worked out for me (based on example script from the author of x3270 (look at sourceforge).
Amazingly, you will find NOTHING when goggling "x3270 script example". Documentation could be better and is not focused toward dummies like me. Looks like nobody does x3270 scripting, or don't care to share.
I did have a bad time trying to make this script work, hope you save your time.
Enough talking, here it goes:


#! /bin/bash
# TSO login script, which runs as a peer of x3270.
# bash version
# to disconnect user, go to
# www . efglobe . com / cgi-bin / mainframe / mainuser

set -x

# Set up login parameters

# Verbose flag for x3270if

# Define some handly local functions.

# x3270 interface function
function xi
        X3270OUTPUT=6 X3270INPUT=5 x3270if 5>$ip 6<$op $v "$@"
        echo `date +"%H:%M:%S:%N"` 1>&2

# Common x3270 Ascii function
function ascii
        xi 'Ascii('$1')'

# Common x3270 String function
function string
        xi 'String("'"$@"'")'

# x3270 cursor column
function cursor_col
        xi -s 10

# x3270 connection status
function cstatus
        xi -s 4

# Failure.
function die
        xi "Info(\"$me error: $@\")"
        xi "CloseScript(1)"
        exit 1
# loop until expected text appears on screen at given coords and
# send next command followed by enter
# Espera is Wait in portuguese, Envia is Send in portuguese
function Espera-Envia
  texto=$1  #expected text
  coord=$2  #coords from begning of texto (screen initiates at 0,0)
  envia=$3  #command to send

  while [ "$(ascii $coord)" != "$texto" ] && [ $i -lt 20 ]
  do        #sleep 0.5
          xi "Wait(8000,InputField)" #man says timeout is in secs, but I thing it is in millisecs
        xi "Wait(8000,Unlock)"
        xi "Wait(8000,Output)"
        [ $i -gt 10 ] && xi "Wait(1000,NVTMode)" #if other waits dont work, try this...
        let "i +=1"
  [ "$i" = "20" ] && die "Timeout waiting for: " $texto

  [ "$envia" = "" ] && return

  string "$envia"
  xi Enter
  xi "Wait(8000,Unlock)"

# --- MAIN -----------------------------------------------------------
# Set up pipes for x3270 I/O
rm -f $ip $op
trap "rm -f $ip $op" EXIT
trap "exit" INT QUIT HUP TERM
mknod $ip p
mknod $op p

# Start x3270
x3270 -script -model 2 <$ip >$op &
exec 5>$ip        # hold the pipe open
xi -s 0 >/dev/null || exit 1

# Connect to host
xi "Connect($tcp_host)" || die "Connection failed."

# Make sure we're connected.
xi Wait
[ "$(cstatus)" = N ] && die "Not connected."

#---  SCREEN-SCRAPING -------------------------------------

# wait initial menu, choose option TSO
Espera-Envia "Enter"  "20,0,5"  "TSO"

# wait prompt userid, send it.
Espera-Envia "ENTER USERID"  "0,11,12"  "$userid"

# wait prompt PASSWORD, send PASSWORD
Espera-Envia "Password"  "7,4,8"  "$password"

#add userid size to text
#typeset -i nl=18+${#userid}
#Espera-Envia "$userid LOGON IN PROGRESS"  "1,1,$nl"  ""

# Make sure TSO is waiting for a '***' enter
#[ "$(cursor_col)" -eq 5 ] || die "Don't understand logon screen"

# wait ***, send next command
Espera-Envia "***"  "22,1,3"  "IPLINFO"

Espera-Envia "Option ===>"  "3,1,11"  "6"

Espera-Envia "===> "  "5,1,5"  "TSO LISTC"

#enough navegating, you can catch screen with snap action

sleep 800 #so you can watch the screen a little bit.
# Off to ISPF
xi Enter
xi 'CloseScript(0)'

AIXroot 03-04-2011 09:53 AM

yes, I Know, the thread is old. However the thread is good and there isn't out so much about tn3270.
So here are my experiences:

I just compiled it on AIX using gcc-4.4.5-1 and used the following short ksh-script to test TSO availability using a ssl connection, without login:


s3270 -trace << EOF


paleos 09-26-2011 08:34 PM

I realize this is an old post but all the help I could google wasn't enough. I was stumped on this thing for a solid week so I am providing some sample code on how to better interact with s3270 using PHP.


//This is straight from the page. Just sets up an array for your pipes
PHP Code:

<?php $descriptorspec = array(
=> array("pipe","r"),
=> array("pipe","w"),
=> array("pipe","w")

//This opens the process s3270 and enables the pipes for you to read and write from. We will set both to nonblocking and continually page for results later.
PHP Code:

$process proc_open('/usr/local/bin/s3270'$descriptorspec$pipesnullnull);
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0); 

//This function will watch for text on the screen similar to Expect but without having to install an additional module and configure it. Basically until the text shows up on the screen it will continually re-run the ascii() command and wait indefinitely.
PHP Code:

function expecttxt ($thetxt) {
$x false;
$g false;
      while (
$x == false) {
         while (
$mydat fgets($pipes[1])) {
                        if (
preg_match("/$thetxt/i"$mydat)) {
$g true;
                  if (
$g == true) {
                        while (
$mydat fgets($pipes[1])) {
$x true;
fwrite($pipes[0], "ascii()\n");

//This function is the same as above except it will only wait about 10 seconds for a response and then continue running the script.
PHP Code:

function expectemp ($thetxt) {

$g false;
$i 1$i <= 10$i++)  {
           while (
$mydat fgets($pipes[1])) {
                        if (
preg_match("/$thetxt/i"$mydat)) {
$g true;
                        if (
$g == true) {
                                while (
$mydat fgets($pipes[1])) {
$i 11;
fwrite($pipes[0], "ascii()\n");

//You can then use the above functions and run commands real time. I initially did a lot of sleep(x) between commands and set it for a pretty high timeout. This resulted in an extremely inefficient script that STILL wouldn't work because occasionally network latency wouldn't get a response back before the sleep amount was up.
PHP Code:

if(is_resource($process)) {
fwrite($pipes[0], "connect(L:hostname:port)\n");
fwrite($pipes[0], "ascii()\n");
fwrite($pipes[0], "string(session-name)\n");
fwrite($pipes[0], "enter\n");
fwrite($pipes[0], "ascii()\n");
expecttxt("SESSION STATUS");
fwrite($pipes[0], "PF(2)\n");
fwrite($pipes[0], "ascii()\n");
expecttxt("NEXT INFO");


bmolloc 03-01-2012 04:20 AM

doesn't work under WAMP
thank's to paleos for his exemple in PHP. It's work fine on a LAMP server but not under windows.

when i use ws3270.exe in command line ascii() return correct things, but in php all lines are umpty. I use the same php code on linux and on windows.

does some one try it under windows ?

All times are GMT -5. The time now is 03:46 AM.