I have an application which spawns several processes. Is it possible to redirect the output of the children to another hidden terminal so that it does not mix with the parent output and give the ability to the end user to unhide the terminal when needed?
Thanks.
The quick and dirty way to do this is to redirect the child process' output to a (temporary) file.
A terminal tracking that file can then be started using a command like
xterm -e tail -f /tmp/child1.out
This terminal can be closed and opened when needed.
If you'd rather not store the output in a file, you can use a fifo (see mkfifo(1)), but then you lose the ability to see the past output, since a fifo doesn't store data.
from your terminal, run:
touch proc1.log
xterm -e tail -f proc1.log
topuch proc2.log
xterm -e tail -f proc2.log
/run/proc/1.sh >> proc1.log
/run/proc/2.sh >> proc2.log
now you have 2 terminals following the output of the spawned processes
Screen can do this. You can start a detached screen with the new program.
Something like:
screen -d -m -S my-emacs-session emacs foo.c
Related
I am a beginner in bash programming. I want to obtain PIDs from processes, in order to use trap and kill to receive and send signals to a program in the same file.
In particular, I start the program opening a screen in this way:
screen -d -m "start program"
process_id=`/bin/ps -fu $USER| grep "program" | grep -v "grep" | awk '{print $2}'`
The variable process_id contains two PIDs, not one. If I run without a screen, I don't have this issue (anyway, I have to open the screen).
Does anyone have solutions to this problem?
Another question: If I write
screen -d -m "start program">log
the log file isn't printed. Any suggestions?
For your first question, pgrep(or process grep) is what you are looking for.
For instance, the following will return a list of PIDs of all bash processes running.
preg bash
And if you read the docs:
-signal
Defines the signal to send to each matched process. Either the numeric or the symbolic signal name can be used.
Second question, you could either use the -LogFile flag if your version of screen supports it. Or specify the log file in your .screenrc configuration file.
This has already been answered.
Edit:
If you can't access the user's home directory where the configuration file .screenrc is usually put, you could change the $SCREENRC environment variable to explicitly set to an alternative path for it.
So, I have this interactive program that is running on an embedded linux ARM platform with no screen and that I cannot modify. To interact with it I have to ssh into the embedded linux distro, and run the program which is some sort of custom command line with builtin commands, and it does not exit, only SIGINT will quit the program.
I'm trying to automate it by letting it run in the background and communicate with it using pipes by sending SSH commands like this ssh user#host echo "command" > stdinpipe. This part works, I've been provided with an example like this in a shell script (I cannot use bash, I only have ash installed on the machine) :
#!/bin/sh
mkfifo somePipe
/proc/<PID>/exe < somePipe 2>&1 &
I can now easily command the program by writing to the pipe like
echo "command" > somePipe
and it outputs everything inside the terminal. The problem is that while it works if I have an SSH session open, it won't if I only send commands one by one as I said earlier (I'm using paramiko in python with the exec_command() method, just in case, but I don't think that is relevant, I could use invoke_session() but I don't want to have to deal with recv())
So I figured out I'd redirect the output of the program to a pipe. That's where problems arise. My first attempt was this one (please ignore the fact that everything is run as root and stored in the root home folder, that's how I got it and I don't have the time to make it cleaner now, plus I'm not the one managing the software) :
cd /root/binary
mkfifo outpipe
mkfifo inpipe
./command_bin &
# find PID automatically
command_pid=$(ps -a | egrep ' * \.\/command_bin *' | grep -v grep | awk '{print $1}')
/proc/${command_pid}/exe < inpipe 2>&1 &
echo "process ./command_bin running on PID ${command_pid}"
That alone works within the terminal itself. Now if I leave the SSH session open and open another terminal and type ssh root#host "echo command > /root/binary/inpipe" the code gets executed, but then it outputs the command I just typed and its result into the other terminal that stayed open. So it is obviously not an option, I have to capture the output somehow.
If I change ./command_bin & for ./command_bin >outpipe & the program never starts, I have no idea why, I know that because $command_pid is empty and I cannot find the process with ps -A
Now if instead I replace /proc/${command_pid}/exe < inpipe 2>&1 & with /proc/${command_pid}/exe < inpipe &>outpipe & the program starts, I can write to inpipe just fine with echo "command" > inpipe when the script finished running, however if I try any of cat < outpipe, tail outpipe it just hangs, and does nothing. I've tried using nohup when starting the command but it doesn't really help. I've also tried using a normal file for redirecting the output instead of a fifo, but with the exact same results.
I've spent the entire day on this thing and I cannot get it to work. Why is this not working ? Also I am probably just using an awful way to do this, is there any other way ? The only thing that's mandatory here is that I have to connect through ssh to the board and the command line utility has to stay open because it is communicating with onboard devices (using I2C, OneWire protocols etc).
To keep it simple I want to be able to write to the program's stdin whenever I want, get its stdout to go somewhere else (some file, buffer, I do not care) that I can easily retrieve later after an arbitrary amount of time with cat, tail or some other command with ssh.
Is there any tool/command in Linux that I can use to run a command in more than one tab simultaneously? I want to run the same command: ./myprog argument1 argument2 simultaneously in more than one shells (I want to increase this so as to put my code under stress later on) to check if the mutexes are working fine in a threaded program.
I am kind of looking for something like what wall does. I can think of using tty's, but that just seems like a lot of pain if I have to scale this to many more shells.
Why not do something like
for i in {1..100}
do
./myprog argument1 argument2 &
done
This is in case the shell is bash. You can look into other looping constructs in case of other shells.
Running the jobs asynchronously with redirected output is the simplest solution, but if you really want each process to run in its own terminal, a good option is to use a terminal emulator like screen or tmux. For example:
yes | sed 5q | while read k; do # iterate 5 times
tmux new-session -d 'sh -c "/path/to/myprog arg1 arg2; sh"'&
done
The trailing sh causes the session to remain alive after myprog terminates, and the intial yes pipeline is used instead of seq since it works where seq is not available (there are lots of ways to iterate!)
Once the sessions are running, you can attach to them individually to view the output. (See tmux documentation for details.)
if you are using gnome terminal, try this one
gnome-terminal --maximize --tab-with-profile=default -e '/bin/sh -c ./myprog argument1 argument2' --tab-with-profile=default -e '/bin/sh -c ./myprog argument1 argument2' --tab-with-profile=default -e '/bin/sh -c ./myprog argument1 argument2'
please check gnome-terminal man page for more options
Use GNU Parallel's --tmux --fg:
parallel -j20 --tmux --fg echo doit {}\; sleep {} ::: {1..100}
Use ctrl-b n and ctrl-b p to cycle between the running terminals.
That way you can keep everything in a single window, but without the output from the jobs mixing.
Install the moreutulis package (with non-GNU parallel) or, preferably, GNU parallel (often packaged separately; SUSE calls it gnu_parallel, Ubuntu and RedHat call it parallel) so you can use parallel. Then figure out how to specify the terminal your command runs in. For example
parallel yourscript -- tty1 tty2 pts6
Then you just have to figure out how to write "yourscript" to take the tty to run on as an argument, which is a separate question. :)
I had the same situation when I was at college and I did something like this
for i in $(seq 1 10)
do
xterm -e "./myprog argument1 argument2"&
done
This spawns 10 xterms each running your program in the background.
From comments it seems you don't need stdin, do need stdout, don't want ptys, don't want screen or tmux.
Easy-peasy:
for seq in `seq 5`; do
./myprog argument1 argument2 >output$seq &
done
Maybe you could (ab)use clusterssh for that?
Open a bunch of terminals, get everything set up, then hit ENTER really quickly in each terminal.
I've got a program running in a GNOME Terminal, but the screensaver is acting up and won't let me back in with my password. While waiting for a fix for the gnome-screensaver bug, is there some way to see the output (or even take over the process) in a virtual console (Ctrl-Alt-F1) without being able to interact with the GNOME Terminal?
Clarification: The original issue was the screensaver, but the question I'd like answered is how to see the output from a process running in another terminal, after starting the process without any logging to file. I'm guessing it should be possible to set the output device of a process from a different shell? Or is it possible to put a process in another shell into background mode, and get it into the foreground in the current shell? Or even ask GNOME Terminal to redirect or copy the output?
I've had luck in the past killing the screensaver from a virtual console, unlocking X session.
# Get the pid (xscreensaver, gnome-screensaver, etc.)
ps -f -u $(whoami) | grep screensaver
kill -9 12345 # Replace 12345 with the real pid
EDIT: Seems like this has been thought of, and you should use one of these commands, depending on which screensaver program you use:
xscreensaver-command -exit
gnome-screensaver-comand --exit
See the man page for those commands for more details.
Usual way is to pipe the output to a file, like program > program.log
Do tail -f program.log in another tab of Gnome console, and the same in the non-X console.
Alternatively, use tee to duplicate the output in the same console: program | tee program.log
ssh in to the box. kill the screensaver. su to become root and kill -9 if it's really acting up.
Usually Gnome-Terminal displays the output of one vty out of /dev. So just connect your console to that vty.
Launch program with screen.
Open another terminal, launch screen -x and you have two terminals acting like one. Try it, it's fun :)
I would like my tcsh script to launch an editor (e.g., vi, emacs):
#!/bin/tcsh
vi my_file
This starts up vi with my_file but first displays a warning "Vim: Warning: Output is not to a terminal" and my keystrokes don't appear on the screen. After I kill vi, my terminal window is messed up (no newlines), requiring a "reset". I tried "emacs -nw", "xemacs -nw", and pico with similar results. "xemacs" works but launches a separate window. I want to reuse the same terminal window.
Is there a way to launch an editor from a script so that it reuses the same terminal window?
I answered my own question! You have to redirect terminal input and output:
#!/bin/tcsh
vi my_file < `tty` > `tty`
The reason you're getting the error is that when you start a shell in your environment, it's starting in a subshell that has STDIN and STDOUT not connected to a TTY — probably because this is in something like a pipeline. When you redirect, you're opening a new connection directly to the device. So, for example, your command line turns
$ vi < `tty` > `tty`
into
$ vi < /dev/ttys000 > /dev/ttys000
So you're not really using your old STDIN/STDOUT, you're creating two new files and mapping them to your vi process's STDIN/STDOUT.
Now, tell us what you're doing with this and we'll tell you how to avoid this kludge.
I wanted to do something similar. I wanted an alias that would find the last file I was working on, and open it in vi(1) for editing. Anyway, I couldn't figure out how to do it as a readable alias (in tcsh) so I just created an ugly shell script (csh because I'm old) instead:
#!/bin/csh
set DIR = "~/www/TooMuchRock/shows/"
set file = $DIR`ls -t $DIR | head -1`
set tty = `tty`
vi $file <$tty >$tty
(1) kraftwerk:bin> which vi
vi: aliased to /usr/local/bin/vim -u ~/.exrc
Absolutely. :-)
Write your script and have it call the EDITOR environment variable, which you will have set to "emacsclient". Then start up Emacs, execute M-x server-start, switch to a shell buffer (M-x shell) and execute your script. Emacsclient will pop up the thing to be edited and C-x # will act as a "done" command and take you back to your script with edits completed or aborted, as you choose.
Enjoy.
Edit: I meant to add that these days Emacs IS my terminal program. I have dozens of shell buffers and never have to worry about losing output and can use all the power of Emacs to manipulate and analyse the terminal output. And have Emacs scripts generate input to the shells. Awesome actually. For example, watching Tomcat output scroll by in a shell buffer while editing sources or processing mail or doing most any Emacs thing is very convenient. When a Tomcat stack trace appears I can quickly respond to it.
Had the same trouble with 'pinfo' in a shell script 'while' loop. The line can be used in the script, it uses 'ps' to find the tty of the current process number, "$$", and stores that tty in $KEY_TTY:
KEY_TTY=/dev/`ps | grep $$ | tr -s '[:blank:]' | cut -d " " -f 3`
Later in the script, just call the tty-only proggie, with $KEY_TTY as input, in my case it was:
pinfo -m $s $page < $KEY_TTY
For 'vi' it'd be:
vi $a < $KEY_TTY > $KEY_TTY
The advantage is that the script as a whole can still accept STDIN input, and 'vi' (or whatever) should work fine -- without having to remember to set any environmental variables before running the script.
Set your terminal tty to a variable, and then redirect the editor i/o through that variable.
In your script:
#!/bin/sh
ls | while read a; do vi $a < $MYTTY >$MYTTY; done
And then execute the script with:
$ MYTTY=`tty` ./myscript >/tmp/log
I was able to get the desired behavior under bash+Cygwin+Terminator:
#!/bin/bash
vim foo
Run the script, vim loads, no error messages, behaves as normal. There are undoubtedly dozens of variations between our setups, however, so I can't hazard a guess as to what makes the difference. I'm curious what it is, but you got it working, which is the important part.