Start tmux session which not closing after running script - linux

How can I create an tmux session with script (e.g.)
tmux new-session python3 --version
If I need the session not to end?

You can achieve this by using the tmux send-keys command which sends commands to an existing session from the command-line (or a script):
tmux new-session -s test -d # Creates a session named 'test' and stays detached.
tmux send-keys -t test "python3 --version" Enter # Sends the command you wanted to the session.
# Here, the command was executed and the session is still alive.
tmux attach -t test # (Optional) If you want to attach to your session after the command was executed.
If the commands you want to send are in a script, you can send as a command the execution of this script:
If the script is python_ver.sh (make sure the script is executable):
#!/bin/sh
python3 --version
Then you'd go:
tmux new-session -s test -d # Creates a session named 'test' and stays detached.
tmux send-keys -t test "./python_ver.sh" Enter # Sends the command you wanted to the session.
# Here, the command was executed and the session is still alive.
tmux attach -t test # (Optional) If you want to attach to your session after the command was executed.

Related

Need a good way to ssh into a pc and run tmux

I want to SSH into a pc from python code and start tmux and attach to the session and run my programs.
I tryd useing paramiko, if i run tmux it crasched beacause it could not attach to session. Only way i could create a session in paramiko is to run
"tmux new-session -s <pannel name> -d"
but problem is still that i cant attach to the session useing
tmux a
The solution i have atm is autopygui python library and useing putty to start the process this solution works, but i need a better solution.
Found an solution on stackexchange since i cant find it on stack overflow i will post it here.
as part of the question with SSH i used paramiko, template here for the paramiko SSH code. In commands array just enter the tmux commands below.
for terminal commands i used
Create a detached session:
tmux new -d -s mySession
Execute a command in the detached session:
tmux send-keys -t mySession.0 "echo 'Hello World'" ENTER
3.1 Attach to the session
`tmux a -t mySession`
3.2 To exit SSH terminal
exit
Solution explanation:
Paramiko can't attach/jump to the new session with paramiko so solution is to use sendkeys in detached mode to execute commands.

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

Screen not starting from rc.local

I have a problem where I am unable to start a screen session at boot using the rc.local file. The specific screen I am starting is for a spigot minecraft server.
This is my rc.local file:
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/home/pi/Documents/bootlog.sh
/home/spigot1_12/startspigot.sh
exit 0
This is the startspigot.sh script (with chmod u+x):
#!/bin/bash
cd /home/spigot1_12
boot=$(date)
echo "Starting spigot server in screen \"minecraft\" # $boot " >> /home/pi/Documents/minecraftlog
screen -S minecraft java -Xms512M -Xmx1008M -jar /home/spigot1_12/spigot-1.12.jar nogui
The minecraftlog file does update at each boot, so the script is run.
When I run the command "sudo sh startspigot.sh", everything works perfectly. The screen is started and the minecraftlog file is updated. I can find the screen again with "sudo screen -ls"
At boot, however, both "sudo screen -ls" and "screen -ls" return no sockets.
What can be causing this? The only two users are "pi" and root.
Thanks in advance!
Starting a script in a new detached screen as current user (rc.local = root):
screen -dmS <session name> <command>, example:
screen -dmS screenName bash /home/user/run.sh
Starting a script from rc.local as user:
runuser -l user -c 'screen -dmS screenName bash /home/user/run.sh'
Running screen in detached mode (when you do not have active terminal, like in rc.local or crontab):
screen -dm -S <session name> <command>
-d -m Start screen in "detached" mode
-S When creating a new session, this option can be used to specify a meaningful name for the session.

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

Resources