create screen session that doesn't terminate with the program - linux

I'm working on a startup script that is initiated from rc.local. I start up several programs with
screen -d -m my-prog
and that works great. However, if one of the programs has problems and exits, so does the session. I'd like to be able to have the session stick around so I can attach to it and see the output from the program before it crashed.
Is there a way to do this? I thought about
screen -d -m bash -c my-prog
But again, if my-prog terminates then so does bash and then so does screen.

You can follow the answer at https://unix.stackexchange.com/questions/47271/prevent-gnu-screen-from-terminating-session-once-executed-script-ends
They suggest something like you were trying in your second attempt, but instead of using bash to invoke the command (which terminates with the command as you noted), invoke bash after the command finishes like:
screen -dmS session_name sh -c 'my-prog; exec bash'

Related

Attach to a GNU screen and then execute commands

I have seen some similar questions asked but the solutions don't seem to work in my case.
I am trying to SSH into a specific screen instance on a Node machine and then execute some commands
My current process is this:
On the remote machine I create a screen instance:
screen -dmS "my_screen"
From my local machine I do something like:
ssh <user>#<remote> -a -x -t screen -x -r my_screen -X stuff 'ruby my_script.rb'
but the output is just:
Connection at (ip) closed.
and the ruby script is not run.
If I separate the commands then the script runs correctly eg:
ssh <user>#<remote> -a -x -t screen -x -r my_screen
it connects to the screen, and then I manually enter:
ruby my_script.rb
exit
Then the script executes in the screen as intended.
What is the correct way to send commands to a screen?
In your second example, you are executing the command by typing it into the console. If that is the behavior you want to emulate, you can use the stuff command to have screen paste your text into the console to execute it.
ssh <user>#<remote> -a -x -t screen -x -r my_screen -X stuff \"ruby my_script.rb^M\"
(Note the ^M was generated using CTRL-V, CTRL-M).
This won't display anything to your open terminal, but when you reconnect to the screen, you should see the output of your command (assuming the screen was at a console window at the time you sent the command, which is the risk with this approach).
You should be using exec instead of stuff. As the name implies, exec executes commands inside the screen
ssh <user>#<remote> -a -x -t screen -x -r my_screen -X exec ruby myscript.rb

Having problems running python script even when putty is closed

So basically, I have a bot I'm running, and I would like for it to keep running even when I exit putty.
I've tried using nohup python bot.py & but it still ends the python bot when I close the putty program. I've also tried using a run.sh file with /usr/bin/nohup bot.py & inside it. but it won't work :( is there something else I'm missing?
I have also made sure the run.sh is a executable as some other forums have suggested, and I still get can't open run
I'm kinda new to the linux terminal.
if you guys could help me out that would be awsome :)
You need to detach the terminal so that when you exit, it is still running. You can use screen or tmux or some other multiplexer.
Here is how to do with screen:
screen -S mybot -m -d /usr/bin/python /path/to/bot.py
-S give the session a name (this is useful if you want to attach later. screen -D -R mybot)
-m always create a new session
-d detach (launch the program, but then detach the terminal returning you to the prompt)

How to reset tty after exec-ed program crashes?

I am writing a Ruby wrapper around Docker and nsenter. One of the command my tool provides is to start a Bash shell within a container. Currently, I am doing it like this:
payload = "sudo nsenter --target #{pid(container_name)} --mount --uts --ipc --net --pid -- env #{env} /bin/bash -i -l;"
Kernel.exec(payload)
In Ruby, Kernel#exec relies on the exec(2) syscall, hence there is no fork.
One issue is that the container sometime dies prematurely which effectively kills my newly created Bash prompt. I then get back the prompt originally used to run my Ruby tool, but I cannot see what I am typing anymore, the tty seems broken and running reset effectively solves the issue.
I'd like to conditionally run reset if the program I exec-ed crashes. I found that the following works well:
$ ./myrubytool || reset
Except I'd like to avoid forcing people using my tool to append || reset every time.
I have tried the following:
payload = "(sudo nsenter --target #{pid(container_name)} --mount --uts --ipc --net --pid -- env #{env} /bin/bash -i -l) || reset;"
But this surprisingly puts reset in the background (i.e. I can run reset by entering fg). One benefit is that the tty is working properly, but it's not really ideal.
Would you have any idea to solve this issue?
If terminal echo has been disabled in a terminal, then you can run the command stty echo to re-enable the terminal echo. (Conversely, stty -echo disables terminal echo, and stty -a displays all terminal settings.)
This is safe to run even if terminal echo is already enabled, so if you want to play it safe, you can do something like ./myrubytool ; stty echo which will re-enable terminal echo if it is disabled regardless of the exit status of your Ruby program. You can put this in a shell script if you want to.
It might be that there is a way to execute a command when the Ruby program exits (often referred to as a "trap"), but I'm not familiar enough with Ruby to know whether such capabilities exist.
However, if you are creating a script for general use, you probably should look into more robust techniques and not rely on workarounds.
How about this? It should do exactly what you want.
It runs the command in a separate process, waits on it, and if, when it finishes, the return value is not 0, it runs the command reset.
payload = "sudo nsenter --target #{pid(container_name)} --mount --uts --ipc --net --pid -- env #{env} /bin/bash -i -l;"
fork { Kernel.exec(payload) }
pid, status = Process.wait2
unless status.exitstatus == 0
system("reset")
end
EDIT
If all you want to do is turn echo back on, change the system("reset") line to system("stty echo").

Using screen in bash script

I'm running a game server on a remote server where I use a detached screen instance to leave it running.
I'm now creating a script that can be used to shut down the server, back up all the vital files and start it up again, however I'm having a few difficulties with dealing with the screen.
I assumed that I could just switch into the detached screen in the script (after the server had already been shut down) by calling screen -r in the script.
But that doesn't seem to work because if I run the script from outside screen it just launches the server in that session.
screen -r
cd ~/servers/StarMade/
sh StarMade-dedicated-server-linux.sh
screen -d
This is what I thought would do the trick but it doesn't. Maybe somebody can help me out here. I'm not a bash expert. In fact this is propably my first bash script that doesn't include "Hello World". Thanks.
Your script, as in your example, will get executed by your sell, not the one in the screen. You need to tell the running screen to read a file and execute it - that's what the -X option is for.
Try
tempfile=$(mktemp)
cat > $tempfile <<EOF
cd ~/servers/StarMade/
sh StarMade-dedicated-server-linux.sh
EOF
screen -X readbuf $tempfile
screen -X paste .
rm -f $tempfile
You can leave screen running in a 2nd terminal session to see what happens.

starting script in screen

I want to start a python script within screen from a script. I tried this
screen -dmS gateway_monitor;screen -r gateway_monitor -p 0 -X '/usr/bin/python /root/Gateway.py'
but if I reattach to the screen afterwards, it's just empty and looks like
nothing has been executed at all. Any clues why this is or how I get
achieved what I want?
You can use:
screen -dm bash -c 'python your_script.py'
If you need several commands, use ;:
screen -dm bash -c 'source ~/.bash_profile; python your_script.py'
Documentation:
https://www.gnu.org/software/screen/manual/screen.html:
-d -m: Start screen in detached mode. This creates a new session but doesn't attach to it. This is useful for system startup scripts.
http://linux.about.com/library/cmd/blcmdl1_sh.htm :
-c string: If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.

Resources