LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 02-07-2012, 10:54 AM   #1
Daravon
Member
 
Registered: Mar 2006
Posts: 170

Rep: Reputation: 15
Redirecting (forking?) STDIN?


I know how to do simple output redirection like "ls >> files.txt". In this case I want to (kind of) redirect INPUT.

I'm trying to build scripts for X3270, an emulator. I could manually build them, but it would be sweet to interactively build them.

When you invoke X3270 with the -script option, it pops up the graphical emulator window as usual, but also allows you to enter scripting commands into the same terminal you used to launch the emulator. I guess that simply means the emulator is listening on STDIN. So, in this mode you can enter your commands either into the X-window as usual, or you can enter them in the terminal, and watch their effect on the X-window emulator.

To build a script interactively, it would be sweet to capture all my commands to a file so that I can later pipe them in. In other words when I enter a command like

Code:
Script "\f \t I'm typing this text into the emulator field \t this is the next field \n "
I want it to get sent to the emulator, and ALSO go to a file. So I basically need to fork STDIN somehow. How can I do this?
 
Old 02-07-2012, 12:04 PM   #2
devUnix
Member
 
Registered: Oct 2010
Posts: 606

Rep: Reputation: 59
I don't know anything about the Emulator thingy you have mentioned. For redirection STDIN, it should be straightforward. Does your emulator accept STDIN? If yes, then you can use simple Piping (|) mechanism. If you want to save the input in a file as well then first pipe your commands to "tee" and then use the pipe to give the commands to your program.

Here's an example:

Code:
[root@localhost Desktop]# grep test /etc/passwd | tee user.txt | cut -d ':' -f 7
/bin/bash
[root@localhost Desktop]# cat user.txt
test:x:501:502::/home/test:/bin/bash
[root@localhost Desktop]#
In the above example, the output from "grep" becomes the input to "tee" and then it is saved to an intermediate file. The output then is handed over to "cut" that does its work.
 
Old 02-07-2012, 12:18 PM   #3
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
If your application is a GUI that uses X, it probably does not use stdio to get its input. That, however doesn't answer your question, which has a fairly simple answer. Since the data you are supplying to your script seems to be coming from the commandline, you can simply re-use it as often as necessary.
Code:
#! /bin/bash

# Save the commandline arg to a (new) file.
echo $1 > aFile

# Send the commandline to a program's stdin
echo $1 | X3270
Your script will most likely need to be more elaborate than this, but the fundamental principles should still apply.

--- rod.

Last edited by theNbomr; 02-07-2012 at 12:19 PM.
 
Old 02-07-2012, 01:05 PM   #4
Daravon
Member
 
Registered: Mar 2006
Posts: 170

Original Poster
Rep: Reputation: 15
I may be having conceptual difficulties about what is stdin, what is 'the commandline', etc. Let me explain what I am trying to do, because I don't want to be confusing.

The program "x3270" is an IBM 3270 terminal emulator.

So, I'm running Ubuntu. I open gnome-terminal and run this command:

Code:
x3270 mymainframe.domain.com
into my Linux terminal.

1 thing happens: A window pops up with my emulated 3270 terminal, connected to my mainframe. The Linux terminal that I entered the above command in "finishes" (shows a prompt).

On the other hand if I do this:

Code:
x3270 -script mymainframe.domain.com
This launches x3270 in "script" mode, so 2 things happen:
1. A window pops up like normal, showing the emulated 3270 terminal, connected to the mainframe
2. The Linux terminal into which I entered the above command shows a newline. It does not "finish". I can type scripting commands into THAT terminal and it will control the emulator. I can watch the effects my commands have on the emulated 3270 terminal (I can also interact directly with the emulated terminal in the X window, but that's beside the point right now). When I type scripting commands into the Linux terminal I launched the emulator from, is this not the emulator pulling in data from stdin? If not what do you call it? What is happening if this is not stdin?

I have already found that I can build a script manually, consisting of lines of commands, and then pipe that into x3270. See:

Code:
chaz@optimus:~/bin$ cat smss.sh
#!/bin/bash

x3270 -model 2 -script -reconnect -efont 3270gt16 mymainframe.domain.com 
exit

chaz@optimus:~/bin$ cat testscript.scr
String "login\n"
String "myusername\n"
Wait(10, Seconds)

chaz@optimus:~/bin$ cat testscript.scr | smss.sh 
E U U C(mymainframe.domain.com ) I 2 24 80 0 0 0x40000b2 0.003
ok
E U U C(mymainframe.domain.com) I 2 24 80 0 0 0x40000b2 -
ok
E U U C(mymainframe.domain.com) I 2 24 80 0 0 0x40000b2 -
ok
chaz@optimus:~/bin$
If I do this, an X window is launched, and the output of the Linux terminal shows that the commands are accepted, but the X window goes away after all the commands are entered. Is there any way to pipe the script file in and then NOT kill the window?

To the point of this thread: Instead of manually building and testing a script file, what I want to happen is I just want to start the emulator in -script mode, and then I want everything that I send to the emulator from the Linux terminal to also go to a file myscript.scr. Then when I am finished with my given task, I should have an automatically-correct script to accomplish that task. I don't know if I can do this with a pipe, or what.

Last edited by Daravon; 02-07-2012 at 01:14 PM.
 
Old 02-07-2012, 05:23 PM   #5
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
Okay, that clarifies things considerably.
For your benefit, I will address your confusion about what is stdin, in contrast to the commandline.
In Linux, processes are born with 3 file descriptors. One is for the process's standard input; the stream of input data that they can read. Another is the standard output; the place where their 'normal' output gets written. The third is the standard error stream; where most processes write their error messages and other stuff that might need to be kept distinct from the 'normal' output. When a process is created by its parent, the parent process configures to what devices or files the three file descriptors are attached. The default is generally the 'console' for all three. A bash shell is often the parent, and the symbols like '>', '<', and '|' are used to tell the parent shell how to re-connect one or more of the standard IO streams.
The 'commandline' is really a specific case of argument-passing from a parent process to the child process. When you launch a program using a shell, the commandline strings are given to the program as a simple data structure, and the program must know how to get them and use them, or just ignore them.
So, by your description, it sounds like the x3270 application does in fact read its standard input to receive scripted data. My suspicion is that it does so until the standard input stream closes, at which point the x3270 application terminates. The standard input stream closes when the file from which input is being read is exhausted. In your example case, cat terminates because it runs out of data, and is so doing closes its standard output, which is seen as standard input to the x3270 program. If this theory is correct, you should be able to keep the terminal alive by not closing its standard input.
The following is my inelegant solution. Replace 'cat' in your commandline with something like this:
Code:
#! /bin/bash
#
#  catNoTerminate.sh
#
#  Usage: catNoTerminate.sh testscript.scr | smss.sh
#    

if [ -e someScript.scr ]; then
    rm -f someScript.scr ]
fi

cat $1
while read someString; do
        echo $someString | tee -a someScript.scr
done
This leaves the question of how to tell the application to quit, since its normal method has been taken away. Control-C or Control-D in the parent shell will do the trick.
The script will output the content of a file specified on its own commandline, and start a new x3270 input script as you type the commands to the terminal emulator's standard input.

--- rod.
 
Old 02-10-2012, 04:51 PM   #6
Daravon
Member
 
Registered: Mar 2006
Posts: 170

Original Poster
Rep: Reputation: 15
I'm still trying to get this to work.
I looked at your script and if I understand right, then your script would dump the whole testscript.scr into x3270 then leave it upon for me to type commands into. And then all the commands I type will also go to someScript.scr.

It doesn't seem to do that, if I run

Code:
./pyrocat.sh testscript.scr | x3270 -script mymainframe.domain.com
What happens is that x3270 launches, but the command from testscript.scr don't get fed in. Also, a someFile.scr is not generated. It's basically identical to just running x3270 -script mymainframe.domain.com.


Code:
if [ -e someScript.scr ]; then
    rm -f someScript.scr ]
fi
I understand that part, working on the next two

Code:
cat $1
$1 means standard input, so that means the whole testscript.scr is going to be piped into cat. Which means it will go to x3270. And then cat finishes, because data runs out on cat's standard input when the whole script is piped in. But I don't have any special EOL characters in my testscript.scr, so how does cat know that the data is finished? If I run cat without any redirection, it just waits around for me to type more data into it.

Code:
while read someString; do
        echo $someString | tee -a someScript.scr
done
I don't understand this because I don't know read. My bash guide says that using read this way means one line is read from the standard input and becomes named someString. Since you didn't redirect anything to read, its standard input is the standard output of the bash process which is running this script.

The standard output of the bash process is linked to read somehow (I guess, it must just do that), but what is its standard input? When I run this script, bash creates another child bash process to run the script, right? So how is my keyboard going to get linked to it?

I think I will never understand this stuff.
 
Old 02-10-2012, 05:54 PM   #7
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
Quote:
Originally Posted by Daravon View Post
I'm still trying to get this to work.
I looked at your script and if I understand right, then your script would dump the whole testscript.scr into x3270 then leave it upon for me to type commands into. And then all the commands I type will also go to someScript.scr.

It doesn't seem to do that, if I run

Code:
./pyrocat.sh testscript.scr | x3270 -script mymainframe.domain.com
What happens is that x3270 launches, but the command from testscript.scr don't get fed in. Also, a someFile.scr is not generated. It's basically identical to just running x3270 -script mymainframe.domain.com.
Okay, I assume you named the script I wrote 'pyrocat.sh'. But you didn't use it in the way I suggested. See 'Usage' comment, which was created from your example code that reads
Code:
chaz@optimus:~/bin$ cat testscript.scr | smss.sh
Replace 'cat' with 'pyrocat.sh'.
Quote:
Code:
cat $1
$1 means standard input, so that means the whole testscript.scr is going to be piped into cat. Which means it will go to x3270. And then cat finishes, because data runs out on cat's standard input when the whole script is piped in. But I don't have any special EOL characters in my testscript.scr, so how does cat know that the data is finished? If I run cat without any redirection, it just waits around for me to type more data into it.
No, $1 is not standard input. $1 is the first commandline argument. At runtime, $1 get expanded as 'testscript.scr', which is then an argument to cat. When cat gets one argument, it interprets it to be a filespec, and opens that file and dumps it to its standard output.

Quote:
Code:
while read someString; do
        echo $someString | tee -a someScript.scr
done
I don't understand this because I don't know read. My bash guide says that using read this way means one line is read from the standard input and becomes named someString. Since you didn't redirect anything to read, its standard input is the standard output of the bash process which is running this script.
Almost, but not quite. read gets is input from standard input, which is the keyboard. Then, the value of $someString is echoed to tee, which will send its input to two places: a specifed file, and its standard output. The standard out will be piped to your terminal emulator.
Quote:
The standard output of the bash process is linked to read somehow (I guess, it must just do that), but what is its standard input? When I run this script, bash creates another child bash process to run the script, right? So how is my keyboard going to get linked to it?

I think I will never understand this stuff.
The default standard input IS your keyboard, in a normal shell session. The child bash script inherits that from its parent shell process.

The script that I wrote should forward its input (you, typing) to the terminal emulator and also to a script file. That was my interpretation of what you wanted. If you want something different, sorry for the confusion, and please rephrase your requirements.

--- rod.
 
1 members found this post helpful.
Old 02-10-2012, 08:51 PM   #8
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
An alternative would be to use
Code:
script x3270 -script mymainframe.domain.com
The script command logs whatever is printed on your terminal.

It is not exactly what you would like because it includes backspaces, line feeds, control sequences to change colours and to set terminal emulator window title etc. -- everything that is sent to the terminal. The superfluous data can be reduced by:
Code:
PS1='$ '
script x3270 -script mymainframe.domain.com
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
redirecting stdin in bash script artur Programming 3 12-09-2011 06:07 AM
redirecting /dev/ttyS0 -> stdin goestin Linux - Software 2 10-26-2011 11:34 AM
Redirecting to Files and STDIN ahmedb72 Linux - Newbie 1 07-01-2009 04:01 AM
after redirecting stdin still need to read data from keyboard vrikers Programming 4 10-31-2004 06:11 AM
redirecting stdin and stdout with pipes: convincing apps they're for a terminal? prell Programming 1 09-02-2004 06:38 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 06:39 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration