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.
Related
I'm currently using mobaxterm to launch xterms to connect to a remote server. I use...
xterm screen
I use screen because the connection is unreliable so screen allows me to recover sessions.
What I really want is to call "screen -RR" to reconnect sessions if there, or start a new one, but xterm doesn't allow command line arguments.
I've played around with -e, -ls, -hold, etc but I can't get it to work.
Any ideas?
[Edit]
Additional information...
I've tried...
xterm ./script.sh
with screen -RR in it, but that runs, then exits. -l or -hold doesn't help.
xterm -e /bin/bash -c screen -RR
same problem, exits without giving me a prompt.
My current hack is...
xterm ./mybash
where mybash a sym-link to /bin/bash, and I have a check in .bashrc looking for XTERM_SHELL = mybash, then launching screen -RR, but that runs 2 bash shells, so I have to exit twice to close the window.
xterm -e should work. It takes one or more arguments specifying a command (plus its arguments) to execute under xterm (so it must be the last option).
For example, this should work
xterm -e screen -RR
There's no need to invoke /bin/bash to invoke screen.
I'm wondering if I can get a current command execution time (while command is executing) shown somewhere in the tmux's status line?
The question is a bit old but as I came across this while researching this, here's the answer:
for pid in $(tmux list-panes -a -F '#{pane_pid}'); do
for child in $(pgrep -P $pid); do
ps -p $child -ho etime,comm,args;
done;
done
Breaking it down:
First, we get the "first PIDs" for every TMUX pane, change this to narrow down which panels you want to include in your results:
tmux list-panes -a -F '#{pane_pid}'
"First PIDs" mean the PID of the shell, so it'll most likely be your shell (Fish, ZSH, Bash etc). So now we use a for loop to iterate over those PIDs, and for each PID we get the PIDs of processes spawned by that PID, i.e. their children, which is done, inside the loop, by:
pgrep -P $pid
Now we have the child PIDs for each pane, which we can pass to ps to get data on the process. etime is the elapsed time since the process started, comm is the command, and args are the actual arguments, including the actual path of the command being run:
ps -p $child -ho etime,comm,args
The -h flag tells ps to not print the header, while the -o flag sets the output, in this case it's three columns, etime, comm and args.
It's a bit messy as a one-liner, but works:
for pid in $(tmux list-panes -a -F '#{pane_pid}'); do for child in $(pgrep -P $pid); do ps -p $child -ho etime,comm,args; done; done
Or, if you use fish-shell like me, it gets a bit better, though it's still not as clean as I'd like:
for pid in (tmux list-panes -a -F '#{pane_pid}'); for child in (pgrep -P $pid); ps -p $child -ho etime,comm,args; end; end
Still, this does the job, although a bit hackishly. Though, keep in mind, this doesn't check whether the process is running in the foreground, so if you daemonize stuff (&, using Ctrl+Z etc) you will get data for those too, filtering daemons, pipes or whatever may be possible but I wanted all the data so I didn't look into any of those.
I have a long list of remote hosts and I want to run a shell command on all of them. The command takes a very long time, so I want to run the command inside screen on the remote machine, disconnecting immediately from each, and I want the terminal output on the remote to be preserved after the command exits. There is a "tag" that should be supplied to each command as an argument. I tried to do this with parallel, something like this:
$ cat servers.txt
user1#server1.example.com/tag1
user2#server2.example.com/tag2
# ...
$ cat run.sh
grep -v '^#' servers.txt |
parallel ssh -tt '{//}' \
'tag={/}; exec screen slow_command --option1 --option2 $tag other args'
This doesn't work: all of the remote processes are launched, but they are not detached (so the ssh sessions remain live and I don't get my local shell back), and once each command finishes, its screen exits immediately and the output is lost.
How do I fix this script? Note: if this is easier to do with tmux and/or some other marshalling program besides parallel, I'm happy to hear answers that explain how to do it that way.
Something like this:
grep -v '^#' servers.txt |
parallel -q --colsep / ssh {1} "screen -d -m bash -c 'echo do stuff \"{2}\";sleep 1000000'"
The final sleep makes sure the screen does not die. You will have 1000000 seconds to attach to it and kill it.
There is an awful lot of quoting there - especially if do stuff is complex.
It may be easier to make a function that computes tag on the remote machine. You need GNU Parallel 20200522 for this:
env_parallel --session
f() {
sshlogin="$1"
# TODO given $sshlogin compute $tag (e.g. a table lookup)
do_stuff() {
echo "do stuff $tag"
sleep 1000000
}
export -f do_stuff
screen -d -m bash -c do_stuff "$#"
}
env_parallel --nonall --slf servers_without_tag f '$PARALLEL_SSHLOGIN'
env_parallel --endsession
Is there a way to show the command which is currently running at a tmux pane?
I tried 'history', but it does not seem to show the commands which I had executed at tmux.
I also tried 'ps -ef', but it does not show the full command in the case like "./a.sh ; ./b.sh"
I found several answers online that include ps ... | tail -1. Unfortunately, these don't always work because sometimes the order of the commands is swapped, e.g. for two separate panes I get:
$ ps -t /dev/pts/12 -o args=
-bash
mpv some_movie.mp4
$ ps -t /dev/pts/10 -o args=
micro some_file.txt
-bash
I really wanted a single line of output so that I could show it in the status bar, but what I ultimately ended up going with is ps --forest via run-shell. It seems to always reliably show the correct order and with more information should there be nested commands running (e.g. via a bash script). Its output looks like:
$ ps --forest -o args -g $$
COMMAND
-bash
\_ ps --forest -o args -g 1695
Solution
So in my .tmux.conf, I've got:
bind '`' run-shell 'ps --forest -o pid,args -g #{pane_pid}'
It will replace the contents of your pane with the output from the ps --forest command. Once you type esc or ^C, the ps output disappears, and your pane goes back to whatever it was doing :) Ends up looking like:
running script.sh, which calls other-script.sh, which sleeps for 30s
viewing pane process tree via keybinding
(Old question but for future reference)
Try: tmux list-panes -t <your_pane_name> -F '#{pane_current_command}'
https://man7.org/linux/man-pages/man1/tmux.1.html#FORMATS
Try setting pane-border-status to bottom or top in your configuration file, with the tmux command prompt or just running tmux set pane-border-status bottom. Borders should appear around the panes and info about the current process appears much like in a regular terminal window's title bar.
I suspect the command wasn't written to the history file as the shell with the stuck/long-running job wasn't done yet.
You might try pstree -U to see process in their parent/child tree.
launching rsync in named screen so I can reattach to check progress, how can I run a command after the rsync, as is it launches the screen then immediately executes the command?
screen -dmS name rsync
ssh user#hostname 'rm -r ~/path/*'
I'm trying to delete the symlinks of file copied by the rsync,, kind of a "copy once" I don't want to delete source files though.
I suggest running the command inside screen. You could do this by creating a shell script, but in this case the sh -c trick should be sufficient.
screen -dmS name sh -c "rsync args_go_here; ssh user#hostname 'rm -r ~/path/*'"