Linux - NewbieThis 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
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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?
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.
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.
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.
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.
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.
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.
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'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.
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.
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:
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.