Startup script to start a detached screen and run a bash script inside - bash

I have an issue with a startup script I've written and can't for the life of me figure out what's wrong. In essence, I want to start a detached screen, pass a daemon start command into the screen, then change directory and run "npm start" at the directory I've changed to.
Preferably, I'd like to install the screen script as a service, but I've had no success. Screens won't start at all. I've screen -list and even sudo screen -list while the service was installed. I've tried Type=forking Type=oneshot and still nothing.
Crontab is the only thing that has somewhat so far.
I've gotten the screen to stay open, however when I reattach to the screen I get the error:
/path/to/script.sh : 6: /path/to/script: npm: not found.
I used nvm to install node and npm. I tried linking to /usr/bin or /usr/local/bin with no success. Either errors with too many links, or node not found, even though its been linked.
For the scripts I have, the main script which starts the screens is
#!/bin/sh
SCRIPT_DIR=/path/to/script/folder/in/user/directory
screen -dmS nameofscreen bash -c $SCRIPT_DIR/script_to_run.sh
and the script that is supposed to be run is as follows:
#!/bin/sh
USR_BIN=/usr/local/bin
$USR_BIN/daemon_to_start -arg1 -arg2 &&
sleep 2
cd /path/to/npm/app/folder && npm start
sleep 3
exec $SHELL
Once again, with these scripts, the screen starts and stays open, however npm not found error is thrown. Also, if I use the absolute directory for npm, node not found becomes the new error. I've spent three days on this and never wrote a script. I'm starting to lose my mind.
PLEASE HELP!
EDIT: With the help of lojza and adding the node binary to my PATH, It somewhat works! Now when the startup script runs, only one screen is started. The script is supposed to start 4 screens. I've tried appending & and even && to the end with no luck. I will continue searching.

Call npm with full path:
/path/to/npm/app/folder/npm start
/usr/local/bin/npm start #in my case
or
cd /path/to/npm/app/folder && ./npm start

Related

How to run Electron app independent of terminal?

I am looking for a way to run an Electron app (npm startcommand) independently of the terminal itself. Meaning that I expect the Electron app to keep running even if the terminal closes..
I am not sure whether it is possible.
I have tried cd electron-directory-path && nohup npm start &, but this though allows me to use the terminal instance for other commands and prevents any electron messages from popping up in the terminal. But, closing the terminal still kills the Electron app.
Even cd electron-directory-path && npm start & does the same thing, but I haven't yet been able to find a way to run the Electron app completely independent of the terminal instance...
You start an Electron app through nohup npm start &, but when closing the terminal window, the Electron app also terminates (against expectation).
I can reproduce the behavior, but not all the times. In roughly 30% of my experiments, the Electron app was not terminated. I was not able to find the reason for this varying behavior yet.
Workaround
The following workaround closes the terminal without terminating the Electron app. In my tests, it has worked every time:
Start the Electron app as before: nohup npm start &
Close the running terminal by issuing nohup kill $$ &
The $$ gives the current process id.
Note that kill $$ doesn't work.
If you don't necessarily need to run from a terminal, you can also create a desktop file to start the app.
Let pathname be the path to the node app location.
Just use the command:
cd pathname && npm start && ^Z &
cd to change directory to where we need to execute the terminal command.
&& to mean there are other commands to be executed after this one.
npm start to start npm app
^Z to suspend the process running in the terminal, and hence disconnect the terminal part of node from the original app.
& to mean that we don't want the terminal to wait for the command to execute.
Now we can close the terminal, and the electron app should keep running...!
Credits:
https://tecadmin.net/close-terminal-without-killing-running-processes-on-linux/

How to daemonise a shell-script in FreeBSD (and macOS)

The way I normally start a long-running shell script is
% (nohup ./script.sh </dev/null >script.log 2>&1 & )
The redirections close stdin, and reopen stdout and stderr; the nohup stops HUP reaching the process when the owning process exits (I realise that the 2>&1 is somewhat redundant, since the nohup does something like this anyway); and the backgrounding within the subshell is the double-fork which means that the ./script.sh process's parent has exited while it's still running, so it acquires the init process as its parent.
That doesn't completely work, however, because when I exit the shell from which I've invoked this (typically, of course, I'm doing this on a remote machine), it doesn't exit cleanly. I can do ^C to exit, and this is OK – the process does carry on in the background as intended. However I can't work out what is/isn't happening to require the ^C, and that's annoying me.
The actions above seem to tick most of the boxes in the unix FAQ (question 1.7), except that I'm not doing anything to detach this process from a controlling terminal, or to make it a session leader. The setsid(2) call exists on FreeBSD, but not the setsid command; nor, as far as I can see, is there an obvious substitute for that command. The same is true on macOS, of course.
So, the questions are:
Is there a differently-named caller of setsid on this platform, that I'm missing?
What, precisely, is happening when I exit the calling shell, that I'm killing with the ^C? Is there any way this could bite me?
Related questions (eg 1, 2) either answer a slightly different question, or assume the presence of the setsid command.
(This question has annoyed me for years, but because what I do here doesn't actually not work, I've never before got around to investigating, getting stumped, and asking about it).
In FreeBSD, out of the box you could use daemon -- run detached from the controlling terminal. option -r could be useful:
-r Supervise and restart the program after a one-second delay if it
has been terminated.
You could also try a supervisor, for example immortal is available for both platforms:
pkg install immortal # FreeBSD
brew install immortal # macOS
To daemonize your script and log (stdout/stderr) you could use:
immortal /path/to/your/script.sh -l /tmp/script.log
Or for more options, you could create a my-service.yml for example:
cmd: /path/to/script
cwd: /your/path
env:
DEBUG: 1
ENVIROMENT: production
log:
file: /tmp/app.log
stderr:
file: /tmp/app-error.log
And then run it with immortal -c my-service.yml
More examples can be found here: https://immortal.run/post/examples
If just want to use nohup and save the stdout & stderr into a file, you could add this to your script:
#!/bin/sh
exec 2>&1
...
Check more about exec 2>&1 in this answers https://stackoverflow.com/a/13088401/1135424
And then simply call nohup /your/script.sh & and check the file nohup.out, from the man
FILES
nohup.out The output file of the nohup execution if stan-
dard output is a terminal and if the current
directory is writable.
$HOME/nohup.out The output file of the nohup execution if stan-
dard output is a terminal and if the current
directory is not writable.

How do you run a shell command in the background and suppress all output?

I'm trying to write a Shell script (for use in Mac OSX Termninal) that will run a command to start a development server (gulp serve). I have it working except the server is continuously running so it doesn't allow me to enter subsequent commands in the same window without stopping the server (Control+C). My question is, is there a way I can run the process in the background and/or suppress any/all output? My goal is to also write a 'stop server' command that will kill the process (which I'm also unsure how to do). I've tried all combinations of using ampersands and &>/dev/null and nothing quite works. Here's what I have so far:
if [ "$1" = "server" ]
then
if [ "$2" = "on" ]
then
cd / & gulp serve --gulpfile /server/example/gulpfile.js # the output is still shown
printf "\033[0;32mserver is online.\033[0m\n"
else
killall tail &>/dev/null 2>&1 # this doesn't kill the process
printf "\033[0;32mportals is offline.\033[0m\n"
fi
fi
You're doing the output redirection on killall, not gulp, so gulp will continue to merrily split out text to your terminal. Try instead:
cd / && gulp server --gulpfile /server/example/gulpfile.js >/dev/null 2>&1 &
Secondly, your kill command doesn't kill your process because you're not telling it to; you're asking it to kill all tail processes. You want instead:
killall gulp
These modifications should be the most direct path to your goal. However, there are a few additional things that may be useful to know.
Process management has a long history in the *nix world, and so we've been inventing tools to make this easier for a long time. You can go through re-inventing them yourself (the next step would be to store the PID of your gulp process so that you can ensure you only kill it and not anything else with "gulp" in the name), or you can go all the way and write a system monitoring file. For Linux, this would be SysV, Upstart, or systemd; I'm not sure what the OS X equivalent is.
However, since you're just doing this for development purposes, not a production website, you probably don't actually need that; your actual goal is to be able to execute ad-hoc shell commands while gulp is running. You can use terminal tabs to do this, or more elegantly use the splitting capabilities of iTerm, screen, or tmux. Tmux in particular is a useful tool for when you find yourself working a lot in a terminal, and would be a useful thing to become familiar with.
First, to run the process in the background
cd / && gulp serve --gulpfile /server/example/gulpfile.js > /tmp/gulp.log &
after cd you need && (and) and & to run in the background at the end.
To kill all gulp processes
killall gulp

nohup and enter will stop the process: why?

My script needs root privileges and I want to run it on a remote machine and then be able to turn off my local computer.
So I did:
$ nohup sudo ./myScript arg1 &
... which I always do, but on a different machine where I'm always root, so without sudo. For some reason now it's not working:
nohup sudo ./myScript.sh 1 & //then I press enter twice
[8] 24264
me#my-laptop:~/myFolder$ nohup: ignoring input and appending output to `nohup.out'
[8]+ Stopped nohup sudo ./myScript.sh 1
What am I doing wrong here?
Try this:
sudo nohup ./script
After answering the password prompt, type Ctrl-z to suspend it, and bg to put it into the background.
This is especially helpful if you are half-way through running a long process when you decide it needs to be run in the background.
As mentioned in other answers, if a background process started with nohup tries to read from or write to the terminal, it is put into the "Stopped" state. The sudo process that you're executing tries to read your password from the terminal, so the process is stopped (for some reason, the reading seems to be triggered when Enter is pressed).
So, to avoid this, you ned to make sure to enter your password and become root before nohup is executed. For example, like this:
sudo bash -c 'nohup ./myScript.sh arg1 &'
One option here is use the screen utility. Start screen, run your script, detach using CTRL+A, D. Later, log back in, reconnect to the process by running screen again.

Hudson-CI launched screen session terminates when task ends

The main problem I'm having is to background a screen session from Hudson-CI. The shell steps are that I need to start a screen session from a script that is launched by another script. Heres' a simple test:
test.sh:
#!/bin/bash
myscreen.sh
myscreen.sh:
#!/bin/bash
screen -dm -S myscreen pingit.sh
pingit.sh:
#!/bin/bash
ping google.com
If I run ./myscreen.sh I get a screen launched that runs the ping continuously without a problem.
If I run ./test.sh, the screen is never started. I'm assuming there's something basic that I'm either forgetting or not understanding, but I can't figure out what. I thought this would work.
The real reason I want to do this is to have Hudson CI launch a continuous-test script which starts as a screen session so that it can continue in the background. What I'm finding is that the screen session terminates once the task is completed in Hudson.
Any ideas on why I can't launch a persistent screen session from a grand-parent script? Or any ideas on how to deal with this?
This is on OSX 10.6, with screen built from source (so it should work the same as linux I think).
If I run your test.sh, I get the error message
./test.sh: Zeile 2: myscreen.sh: Kommando nicht gefunden.
i.e. command not found. You'll have to write ./myscreen.sh, if the current directory is not on the path. (Is it for you? It should not.) The same is valid for the screen call.
Changing both files to
#!/bin/bash
./myscreen.sh
and
#!/bin/bash
screen -dm -S myscreen ./pingit.sh
I can start my screen without any problems.
I'm on Linux (OpenSUSE) with
$ screen --version
Screen version 4.00.03 (FAU) 23-Oct-06
here.
I don't know why I did not find the following references before, but these were the links that helped me solve the problem:
https://serverfault.com/questions/155851/run-gnu-screen-from-script
http://wiki.hudson-ci.org/display/HUDSON/Spawning+processes+from+build
There are 2 issues here - one of screen being persisted after being launched by a grand-parent process. The other that hudson terminates a session after it completes its task.
The screen problem is resolved by zombie'ing the process as follows:
screen -d -m -S myscreen && screen -S myscreen -X zombie qr && screen -S myscreen -X screen pingit.sh
The Hudson-CI problem turns out to be a bug that's easily resolved per the above link. The solution is to add BUILD_ID=something into the shell script. So if the test.sh script from above is actually the Hudson Build shell execute, then it would have to be changed to:
#!/bin/bash
BUILD_ID=dontkillthisprocess
myscreen.sh
Once both of these steps are implemented, things work fine.

Resources