Recording processes spawned when running a shell script - linux

I currently have an issue whilst running a shell script in UNIX which would be easily solved if I could record the processes which are spawned during a run of my script. I'd thought to use the top command and record to a file e.g.
top > tmp.txt
I think this would not be applicable however as it only refreshes periodically. Does anybody know how this would be possible? Ideally it would be something like this:
pid:123 my_script.sh
pid:124 grep...
pid:125 ...
pid:126 ...
You get the idea.
Kind Regards,
JLove

Top has a "batch mode", which will send the latest "top" results to standard output.
You can do something like this:
top -bn3
Which will print the top results three times to standard output.

It sounds like you just want to know the pids of all processes that have your shell script as an ancestor. ps --forest or pstree should give you what you need.

Related

Redirecting input to script running in background

I wrote a script for resizing windows, which require orientation and value in form of fraction, like so:
resize.sh -h 1/2
and it works as expected.
I also added -k flag, which means that script require user input, like so:
resize.sh -k -h
and in the script:
read -rsn 2 fraction
which I parse to get values for numerator and denominator.
This works great from command line, but idea behind this is to bind resize.sh -k -h to some key combination, and pass following two keys as input. But when I run script from keyboard, it run as a background process which is not associated with any tty, so read could not get its input. Is there any way to redirect global input to background process, after running it from keyboard.
What I tried so far:
Redirection to /proc/$$/fd/0, which didn't work.
Redirectiong currently active tty stdin to read, like so:
read -rsn 2 fraction < /dev/pts/0
which actually worked, but problem is that not all windows are terminal, e.g. web browser.
If my question is unclear, please feel free to ask for additional clarifications or details, and thanks in advance :)
You can use a named pipe for the process communication.
I made am example script where the background proces is a function.
#!/bin/bash
pipe_name=/tmp/mypipe$$
mkfifo "${pipe_name}"
resize()
{
read fraction < "${pipe_name}"
echo "Resize window to fraction=${fraction}"
}
resize &
read -p "Enter your fraction: "
echo "${REPLY}" > "${pipe_name}"
rm "${pipe_name}"
thank you both for providing very useful information. The solution is combination of both, actually.
First I modified read command in resize.sh to get input from named pipe, as Walter suggested, than I wrote a new, kinda "wrapper" script, which executes resize.sh in background, and than, since Barmar pointed I need a gui window, it starts very small terminal window running read and passing input to named pipe. Further more, using wmctrl I manage to place small terminal window right where currently active window begins, and hide it below (thanks to openbox per-application properties), so it's technically not visible at all :)
It's really too hacky for my liking, but it was really the only option I could think of at this moment, so until I find the better way, this gets the job done.
Once again, thank you both for directing me toward solution, I really appreciate it, cheers :)

How to run linux application in background which uses shell?

I have an application/binary from a C program which by defaults uses the shell to take inputs from the user. So, when I start the application in background using & it stops automatically, because of the implementation on which I have no access. When I run this code
iStatus = system("./flute-static -send -a232.0.0.1/6666 a.txt &");
It gives output [1] 21970, the pid.
Then if I press another enter, it gives output
[1]+ Stopped ./flute-static -send -a232.0.0.1/6666 a.txt
And obviously it fails to send the data. How can I solve the problem. Please help me. Thanks in advance.
You can try nohup
iStatus = system("nohup ./flute-static -send -a232.0.0.1/6666 a.txt &");
Nohup means: do not terminate this process even when the stty is cut off.
Or You can use screen
https://www.mattcutts.com/blog/a-quick-tutorial-on-screen/
Read Advanced Linux Programming and about the fork system call; you surely want to use fork(2), execve(2), waitpid(2) with some other syscalls(2) and/or perhaps daemon(3) and/or popen(3). Perhaps using strace(1) on the flute-static program might help you understand more of it.
BTW, you might use some FLUTE library (compile MAD-ALCLIB from its source code!), or simply use an HTTP & FTP client library like libcurl
Whatever you do, if a backgrounded process is reading stdin, it is stopped (see signal(7), tty(4) etc...)! Read also the tty demystified

How to open multiple instances of a program in Linux

Say for example, to open multiple instances of gedit editor I wrote a shell script like this-
gedit&
gedit&
gedit&
gedit&
But after I ran my shell script ./example.sh, I can find only one instance of gedit! I've even used the & operator, so that the shell doesn't wait for one instance to finish. Still I cannot see four instances of gedit.
Also I tried directly from the command prompt. If I just enter gedit& on the command line, it showed 1906 ( this is the PID of the newly created gedit process ), started one new gedit instance and returned to prompt again. When I typed gedit& on the command line, it showed 1909 this time, but no new instance of gedit! And I couldn't find any process with PID 1909 in the System Monitor too. Where did this new process go away?
Is the happening specific to gedit? If so, what is the generic behavior when creating multiple instances of a program?
It is specific to gedit. You are likely looking for gedit --new-window &.
From man gedit:
--new-window
Create a new toplevel window in an existing instance of gedit.
I came here, trying to start multiple instances of audacious.
Allowing only one instance is actually harder to implement, because the program needs to find and communicate with the instance already running. This is done via D-Bus. In order to prevent communication with the already started instance you can run the program in another D-Bus session:
nohup dbus-run-session audacious &
nohup dbus-run-session audacious &
Note: nohup will keep the program running even if the terminal is to be closed.
This method should also work for other programs which do not let the user choose between multiple instance vs. one instance.
Beware that this might introduce bugs, if multiple instances are accessing the same configuration files.
Tested with xfce 4.14.1 and dbus 1.12.20
For Scite:
scite -check.if.already.open=false &
A word of caution:
If you, like me, have your system running for multiple months and have edited some of your shortcuts or aliases to open with this hack, then after a while some programs will not start anymore because there are already too many open D-Bus session. In this case you have to kill the started D-Bus sessions, which do not close when the started program closes. The other way around, killing the D-Bus session, will also kill the opened program, so use with care! For me personally, I have some long running autostarted programs which I want to keep open (firefox), so I kill all but the first 10 D-Bus sessions with this:
for pid in $( ps --sort start_time -aux | grep dbus-daemon | tail +10 | awk '{ print $2; }' ); do kill $pid; done
The cleanest solution would be to write a launcher script which waits for the program to finish and then closes the opened D-Bus sessions. But this is a bit more difficult than it seems because it is hard to find the PID of the corresponding D-Bus session.
P.S.: I also used this hack because there seems to be some program on my system which, after a while, slows down the system's default file open dialog to take multiple minutes if not longer to open! Programs then seem to hang when trying to save or open files. A new D-Bus sessions seems to fix this for some reason. While writing this, I found that pkill gvfsd-trash also works and that it may have been this bug. So until this gets shipped, I guess I'll add pkill gvfsd-trash to my crontab.
This seems specific to gedit, perhaps there's some option to turn off the check for a running instance.
Looks like gedit is first looking for a running instance and simply ignores further start-requests (just a wild guess). But the manual page says, that you can open another window:
--new-window
Create a new toplevel window in an existing instance of gedit.
That wouldn't exactly solve your problem, but maybe that's what you were looking for in the first place.
Good luck,
Alex.
Using this in a script. I've found that it does what I need it to:
#!/bin/bash
xterm -e "gedit; bash" &disown

Redirecting stdin through a FIFO

I'm running a server app (written in Java) under GNU/Linux which takes input (from stdin, I guess) and interprets it to run some commands. I dont want to run the app inside a terminal window (I'd like to run a daemon), but I'd still like to be able to input commands whenever I want to. I thought I might be able to do that using fifos, so I created it using mknod. The problem is cat fifofile > java... and cat fifofile | java ... fail with a "file not found" error for some reason.
Using only cat to read and write and the fifo works flawlessly.
Is there any way to fix this, or any other way to achieve the same goal?
So, Minecraft? The best way to do this is to have a bona-fide tty for the console part of the application. screen is an easy way to do that.
Have you tried java < fifofile? What about something like exec 3<&0; exec 0<fifofile; java?
What shell are you using? You might be able to use process substitution or coprocesses if you're using a shell that supports them.

How to tell if a process has ended?

Besides using top, is there a more precise way of identifying if the last executed command has finished if I had to check in a separate session over Putty?
pgrep
How about getting it to run another command immediately after that sets a flag.
$ do_command ; touch I_FINISHED
then when the command finishes it'll create a file called I_FINISHED that you
can look for.
or something more sophisticated that writes to a log file if you're doing it
multiple times.
I agree that it may be a faster option in the long run to have your program write to a log file or create a notification. Just put it at the end of the executed code, past the part that you suspect may cause it to hang.
ps -eo cmd
Lists all processes, and displays the command line, as 'typed' when the command started, so you will be able to tell your script apart from anything else running written in Perl.

Resources