Startup script to run detachted screen, switch user, and run multiple bash commands - linux

I want to create a small startup script that does multiple things in a row in a screen.
The script starts a named, detached screen (screen -S discordbot -d -m works)
The user inside the script is changed (Neither screen -S discordbot -X "su discordbot", screen -S discordbot -X su discordbot, nor screen -S discordbot -d -m bash -c "su discordbot;" seems to work, or at least subsqeuent commands are not executed).
A cd folder change is exectuded.
A java jar or other script is started.
As I run multiple bots, the script needs to be able to do this in slight variation multiple times in a row. Any pointers on how this could be done?

The screen session that you start up will exit as soon as the process that you started exits.
This works, for instance:
$ screen -S discordbot -d -m bash
$ screen -ls
There is a screen on:
2948.discordbot (Detached)
1 Socket in <...>
As does this:
$ screen -S discordbot -d -m bin/discordbot.sh
Where bin/discordbot.sh looks like this:
#!/bin/sh
echo "Sleeping..."
sleep 10
/bin/echo -n "Hit enter to finish this script: "
read
The last two lines to prevent the screen from exiting prematurely. The other various things you want to do within that startup script should also work, assuming that you do this as root so that the su will work without prompting.

Related

how to create and move between screens in a bash.sh script [duplicate]

Was wondering how I can start up a command such as:
while :; do ./myCommand; done;
But instead of doing the usual
screen -S nameOfMyScreen
Then the command
while :; do ./myCommand; done;
Then detach the screen
^a ^d (Control "a" the control "d"
I would like it to start and detach. Thanks!
screen -d -m sh -c "while :; do ./myCommand; done;"
Explanation:
-d -m starts screen in detached mode (create session but don't attach to it)
sh -c commandline starts a shell which executes the given command line (necessary, since you are using the while builtin).
From screen -h, these look useful:
-dmS name Start as daemon: Screen session in detached mode.
-X Execute <cmd> as a screen command in the specified session.
I haven't done this myself, but that's where I'd start.
Update:
The top of the help also says
Use: path/to/screen [-opts] [cmd [args]]
so the -X switch may be to execute a screen command as opposed to a shell command. You might just be able to put your command after the -dmS <name> without any -X switch.

Creating new 'screen' within existing screen

I have a game server. It runs on linux via dotnet. I run this inside a 'screen' session.
However I am struggling with restarting this server.
From outside, it is easy. I just kill existing screen via name and create new one.
However when I want to restart server from inside (existing game process starts new process that runs script that kills named screen and starts new one)
To be specific:
stop.sh:
screen -r gameserver -X quit
start.sh:
screen -L -A -m -d -S gameserver /usr/bin/dotnet /gameserver/game.dll
restart.sh:
/gameserver/stop.sh
/gameserver/start.sh
Now If I run restart.sh programmatically from inside screen, it calls stop.sh, which terminates current screen and also this restart.sh script, so the new one is not started.
I tried to run restart.sh via screen:
screen -L -m -d /bin/bash -c /gameserver/restart.sh
But it still doesn't work...
I would expect this to run restart.sh in new screen, where the 'gameserver' screen will terminate and start new one and after that screen running restart.sh will stop. But no :(
Any ideas?
Cant you just kill this process inside the screen?
Something like
screen -r gameserver kill $(ps aux|grep 'game.dll'|awk '{print $2}') ?
I think you probably should NOT run such a script inside screen. Kill the whole session then re-create it inside screen is kind of weird.
And in your script stop.sh, though using -r with -X may sometime work, it doesn't make much sense. I think you should use -S instead of -r.
Run outside screen:
If you replace stop.sh with screen -S gameserver -X quit, and run restart.sh outside screen, it should work.
Run inside screen:
However, if you really need to run it inside screen, you could try to kill a window instead of terminate the whole session.
stop.sh:
# Create a new window before kill 'server'
# Without this, the session will be terminated if 'server' is the only window
screen
screen -p server -X kill
start.sh:
# Are we in the 'gameserver' session?
if [ "${STY#*.}" = gameserver ]; then
# Create a window named 'server' and run your program in it
screen -t server /usr/bin/dotnet /gameserver/game.dll
else
# Create a new screen session named 'gameserver'
# And it's default window is named 'server'
# -T $TERM to make sure things such as '-t' work
screen -L -A -m -d -S gameserver -t server -T $TERM /usr/bin/dotnet /gameserver/game.dll
fi

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

How do I pass a command to a screen session?

I'm writing a Linux shell script in which I need to start a new screen session, run a node.js server in the screen, then detach from the screen so that my server runs in the background.
Right now, these are the commands I run manually to do this:
screen
node server.js
[detach screen]
However, I need a way to automate this via the script, and if I just use the above commands in a shell script, it creates the screen and gets stuck there. How can I pass the "node server.js" command to the screen command?
EDIT:
Based on the suggested answer I have a script that works, except that I need to manually create a screen and detach from it before I run it. I tried adding screen -d -m as the first line to create a detached screen, but the script hangs after that line.
tempfile=$(mktemp)
indices=`tail -1 debug.log`
cat > $tempfile <<EOF
node server $indices
EOF
screen -X readbuf $tempfile
screen -X paste .
rm -f $tempfile
How can I create and detach a screen with the script?
This didn't work either:
screen
screen -d
It is as simple as this:
screen -md node server.js
This requires the command to run as a service (as it does), otherwise the screen stops immediately.
To optionally also set a name for the session (e.g. "session-name"):
screen -mdS session-name node server.js
You can then attach to the screen with:
screen -rd session-name
If you want to redirect all output to a file, you can do like this:
screen -mdS session-name bash -c 'node server.js &> output.log'
You can then monitor the output with e.g.:
tail -f output.log
You can list your running screens with:
screen -ls
or
screen -list
Example: Start a Python3 web server in a detached screen
Start a Python3 web server listening on port 8000 that serves files in the current directory, in a named
detached screen:
screen -mdS my-web-server python3 -mhttp.server
Or, with logging to a file:
screen -mdS my-web-server bash -c 'python3 -mhttp.server &> output.log'
For Python 2.x it looks like this:
screen -mdS my-web-server bash -c 'python -mSimpleHTTPServer &> output.log'
EDIT: Try this:
tempfile=$(mktemp)
cat > $tempfile <<EOF
node server.js
EOF
screen -S SessionName -X readbuf $tempfile; screen -RdS SessionName
screen -X paste .
rm -f $tempfile
It should create the temp file, create a screen called SessionName and runs the commands, then delete the temp file. Let me know if that works.

Run "screen -S name ./script" command on #reboot using crontab

I've tried adding this to my crontab:
#reboot /root/startup
The "startup" file:
#!/bin/sh
svnserve -d -r /root/svnrepos/mainres
svnserve -d -r /root/svnrepos/mapres --listen-port=3691
screen -S mta ./mtaserver/mta-server > log1
screen -S mapmta ./mapserver/mta-server > log2
exit 0
Now svnserve commands run fine. The problem is with the screen command.
log1 and log2 files have the same content which is: Must be connected to a terminal.
What I'm trying to do is start the 2 executables on startup, and then later have a way to access them.
Is there a way to do this?
You want to add the following options to the 'screen' commands (e.g. before -S): -d -m
From the manpage:
-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.

Resources