Blocking a bash script running with & - bash

I may have inadvertently launched a bash script containing an infinite cycle whose exit condition may be met next century, if ever. The fact is that I launched the script, as I would do with a nohup program, with
bash [scriptname].sh &
so that (as I get it, which is most probably wrong) I can close the terminal and still keep the script running, as was my intention in developing it. The script should run calculation programmes in my absence and let me gather the results after some time.
Now I want to stop it, but nothing seems to do the trick: I killed the programmes the script had launched, I removed the input file the script was getting orders from and - last and most perfect of accomplishments - I accidentally closed the terminal trying to "exit" the script, which was still giving me error messages.
How can I check whether the script is running (as it does not appear in "top")? Is the '&' relevant? Should I just ask permission to reboot the pc, if that will work and kill everything?
Thank you.
[I put a "Hi everyone" at the beginning but the editor won't let me show it. Oh, well. It's that kind of day.]

Ok, I'll put it right here to prove my stupidity, as I wandered the internet shortly (after a long wandering before writing this post) and found that the line:
kill -9 $(pgrep -f [SCRIPTNAME].sh)
does the trick from any terminal window.
I write this answer to help anyone in the same situation, but feel free to remove the thread if unnecessary (and excuse me for disturbing).

Good you found it, here is another way if you do not use bash -c and run it in current shell not a separate shell.
# put a job in background
sleep 100 &
# save the last PID of background job
MY_PID=$!
# later
kill $MY_PID

Related

How to open a command-line application with a command without closing it?

I am trying to write a script that opens a command-line application (sagemath in this case) which on start up will send a certain command down the pipe (attach a script) without closing the application at the end.
I tried something like:
#!/bin/bash
echo "load(\"script.sage\")" | sage
This, of course, opens sage load the script print the output of the script and closes sage. Adding & at the end of the last line didn't work.
I know that technically I can add this script to the list of scripts which are loaded on startup always but this is not what I want. I thought that it might be done be making a dynamic link at some directory to my script, but not sure if there is such a directory and where it is.
Any suggestions?
Edit:
I didn't know about Expect (I'm a youngster in linux). Reading about, following Mark's suggestion, it a bit I managed to solve this. If this is of any interest to anyone in the future then this does the trick:
#!/usr/bin/expect
set timeout 20
spawn sage
expect "sage:"
send "load(\"script.sage\")\n"
interact
#!/usr/bin/expect
set timeout 20
spawn sage
expect "sage:"
send "load(\"script.sage\")\n"
interact
You could use 'screen' depending on how dynamically you need this script to run. See http://linux.die.net/man/1/screen for info on how to use screen.
You can either:
Use nohup to start the program E.g., nohup "load(\"script.sage\")" | sage.
Or, you can use the disown command.

Disown, nohup or & on Mac OS zsh… not working as hoped

Hi. I'm new to the shell and am working on my first kludged together script. I've read all over the intertube and SO and there are many, MANY places where disown, nohup, & and return are explained but something isn't working for me.
I want a simpler timer. The script asks for user input for the hours, mins., etc., then:
echo "No problem, see you then…"
sleep $[a*3600+b*60+c]
At this point (either on the first or second lines, not sure) I want the script OR the specific command in the script to become a background process. Maybe a daemon? So that the timer will still go off on schedule even if
that terminal window is shut
the terminal app is quit completely
the computer is put to sleep (I realize I probably need some different code still to wake the mac itself)
Also after the "No problem" line I want a return command so that the existing shell window is still useful in the meantime.
The terminal-notifier command (the timer wakeup) is getting called immediately under certain usage of the above (I can't remember which right now), then a second notification at the right time. Using the return command anywhere basically seems to quit the script.
One thing I'm not clear on is whether/how disown, nohup, etc. are applicable to a command process vs. a script process, i.e., will any of them work properly on only a command inside a script (and if not, how to initialize a script as a background process that still asks for input).
Maybe I should use some alternative to sleep?
It isn't necessary to use a separate script or have the script run itself in order to get part of it to run in the background.
A much simpler way is to place the portions that you want to be backgrounded (the sleep and following command) inside of parentheses, and put an ampersand after them.
So the end of the script would look like:
(
sleep $time
# Do whatever
)&
This will cause that portion of the code to be run inside a subshell which is placed into the background, since there's no code after that the first shell will immediately exit returning control to your interactive shell.
When your script is run, it is actually run by starting a new shell to execute it. In order for you to get your script into the background, you would need to send that shell into the background, which you can't do because you would need to communicate with its parent shell.
What you can do is have your script call itself with a special argument to indicate that it should do the work:
#! /bin/zsh
if [ "$1" != '--run' ] ; then
echo sending to background
$0 --run $# &
exit
fi
sleep 1
echo backgrounded $#
This script first checks to see if its first argument is --run. If it is not, then it calls itself ($0) with that argument and all other arguments it received ($#) in the background, and exits. You can use a similar method, performing the test when you want to enter the background, and possibly sending the data you will need instead of every argument. For example, to send just the number of seconds:
$0 --run $[a*3600+b*60+c] &

Pausing and resuming a Bash script

Is there a way to pause a Bash script, then resume it another time, such as after the computer has been rebooted?
The only way to do that AFAIK:
Save any variables, or other script context information in a temporary file to establish the state of the script just before the pause. This goes without saying that the script should include a mechanism to check this file to know if the previous execution was paused and, if it was, fetch all the context and resume accordingly.
After reboot, manually run the script again, OR, have the script automatically run from your startup profile script.
Try Ctrl-Z to pause the command. I don't think you can pause it and then resume after reboot unless you're keeping state somehow.
You can't pause and resume the same script after a reboot, but a script could arrange to have another script run at some later time. For example, it could create an init script (or a cron job, or a login script, etc) which contained the tasks you want to defer, and then removed itself.
Intriguing...
You can suspend a job in BASH with a CTRL-Z, but you can't resume after a reboot. A reboot initializes the machine and the process that was suspended is terminated.
However, it might be possible to force the process into a coredump via a 'kill -QUIT $pidand then usegdb` to restart the script. I tried for a while, but was unable to do it. Maybe someone else can point out the way.
If this applies to your script and the job it does, add checkpoints to it - that means places where all the state of the process is saved to disk before continuing. Then have each individual part check if the output they have to produce is already there, and skip running if it is. That should make a rerun of the script almost as efficient as resuming from the exact same place in execution.
Alternatively, run the script in a VM. Freeze the VM before shutting down the real system and resume it afterwards. It would probably take a really huge and complex shell script to make this worth it, though.

Shell script that can check if it was backgrounded at invocation

I have written a script that relies on other server responses (uses wget to pull data), and I want it to always be run in the background unquestionably. I know one solution is to just write a wrapper script that will call my script with an & appended, but I want to avoid that clutter.
Is there a way for a bash (or zsh) script to determine if it was called with say ./foo.sh &, and if not, exit and re-launch itself as such?
The definition of a background process (I think) is that it has a controlling terminal but it is not part of that terminal's foreground process group. I don't think any shell, even zsh, gives you any access to that information through a builtin.
On Linux (and perhaps other unices), the STAT column of ps includes a + when the process is part of its terminal's foreground process group. So a literal answer to your question is that you could put your script's content in a main function and invoke it with:
case $(ps -o stat= -p $$) in
*+*) main "$#" &;;
*) main "$#";;
esac
But you might as well run main "$#" & anyway. On Unix, fork is cheap.
However, I strongly advise against doing what you propose. This makes it impossible for someone to run your script and do something else afterwards — one would expect to be able to write your_script; my_postprocessing or your_script && my_postprocessing, but forking the script's main task makes this impossible. Considering that the gain is occasionally saving one character when the script is invoked, it's not worth making your script markedly less useful in this way.
If you really mean for the script to run in the background so that the user can close his terminal, you'll need to do more work — you'll need to daemonize the script, which includes not just backgrounding but also closing all file descriptors that have the terminal open, making the process a session leader and more. I think that will require splitting your script into a daemonizing wrapper script and a main script. But daemonizing is normally done for programs that never terminate unless explicitly stopped, which is not the behavior you describe.
I do not know, how to do this, but you may set variable in parent script and check for it in child:
if [[ -z "$_BACKGROUNDED" ]] ; then
_BACKGROUNDED=1 exec "$0" "$#" & exit
fi
# Put code here
Works both in bash and zsh.
the "tty" command says "not a tty" if you're in the background, or gives the controlling terminal name (/dev/pts/1 for example) if you're in the foreground. A simple way to tell.
Remember that you can't (or, not recommended to) edit the running script. This question and the answers give workarounds.
I don't write shell scripts a long time ago, but I can give you a very good idea (I hope). You can check the value of $$ (this is the PID of the process) and compare with the output of the command "jobs -l". This last command will return the PID of all the backgrounded processes (jobs) and if the value of $$ is contained in the result of the "jobs -l", this means that the current script is running on background.

bash script doesnt run correctly as background process

I have bash script which works well but when I send it back with nohup script &
and close my terminal session then it's not working correctly. It only works well within my terminal session open.
What could be possible reasons which affects my script run not correctly without my terminal session? Could it be one of the terminal variables or something?
solaris 10
call:
script &
disown $!
& launches your script in the background and disown $! detaches last executed command from the current shell. $! is the PID of the last background executed command.
Without the source we can only make guesses. However, your usecase might be a good fit for using GNU Screen: http://www.gnu.org/software/screen/ You can detach shell sessions from your current login and pick them up later on.
In my humble opinion one of the most useful programs on earth ;)

Resources