GNU screen hack-fu: running one command in multiple windows
I’ve long used the wonderful GNU screen text-windowing system, which allows you to do lots of neat things like detach a terminal session and reattach later, and switch between multiple terminal `windows’ within a single session.
When you have lots of gnu screen windows open, sometimes it’d be nice to run the same command on several of them — for example, cd several windows to the same directory, or ssh to the same server. I’ve always done this by copy-and-pasting, though there are some funky commands in screen for copying and pasting text between windows.
Now, thanks to the screen -X command and a short shell script, I can do this very easily.
I name the script screenex, and use it as follows:
[03:36 PM mithras@powerbook: ~] screenex 1 6 ls
In windows 1 - 6, doing: ls
I simply pass the range of window numbers to run the command in, followed by the command itself. I can also omit the second number, to execute the command on just one other window:
[03:39 PM mithras@powerbook: ~] screenex 2 pine
In windows 2 - 2, doing: pine
Neat! This becomes much more powerful, though, when you add substitution of the window number. When you include the token –INDEX– in the command, the window number is substituted for –INDEX–. I use this to launch ssh connections to six machines at once, which is handy when I’m running a bunch of jobs in parallel. At work we have a bunch of servers, named server1.school.edu, server2.school.edu, etc. So to connect to a different machine in each window, I just run:
[03:41 PM mithras@powerbook: ~] screenex 1 6 ssh server–INDEX–.school.edu
In windows 1 - 6, doing: ssh server–INDEX–.school.edu
And I’m connected, ready to run my parallel jobs! You can also do cool stuff if you have environment variables that are indexed by number, for example WORKINGDIR1, WORKINGDIR2, etc. Anyway, I’ll save more for later.
The script:
(Note that the ^M character is a literal newline character, which you can enter in vi by typing ctrl-V, then enter.)
#!/bin/sh # # command to run the given command on multiple `GNU screen' windows # usage: screenex [begin-window] [end-window] command # # by Mithras The Prophet (mithras.the.prophet, which is a gmail account.) # # # returns 1 if arg is numeric, 0 otherwise # is_numeric() { var="$1" if [ -z "$var" ]; then echo "0" else [ "$var" -eq 0 ] 2> /dev/null if [ $? -eq 0 -o $? -eq 1 ]; then echo "1" else echo "0" fi fi } # # if argument 1, or arguments 1 and 2 are numeric, then # we apply the command to just that range of windows; # otherwise, to all windows # mycommand="" window_begin="1" # beginning of range of windows to send command to window_end="6" # and end arg1="$1" shift; if [ -z "$arg1" ]; then exit; fi if [ $(is_numeric "$arg1") -eq 1 ]; then # this is beginning of range window_begin="$arg1" # try to grab a second numeric arg? arg2="$1" shift; if [ $(is_numeric "$arg2") -eq 1 ]; then # we have a second number! window_end="$arg2" # get start of command arg3="$1" shift; mycommand="$arg3" else # ahve second arg, but not a number # so it must be start of command window_end="$window_begin" # just do the one window mycommand="$arg2" fi else # arg1 -not- numeric, # so it must be start of command mycommand="$arg1" fi while [ ! -z "$1" ] do mycommand="$mycommand \"$1\"" # rest of line shift done echo "In windows $window_begin - $window_end, doing: $mycommand" # # now execute! # newline=<<EOQ EOQ let "window_end = $window_end + 1" # so we can do strict -lt test index="$window_begin" while [ $index -lt $window_end ] do thiscommand=${mycommand//--INDEX--/$index} screen -X at ${index}# stuff "${thiscommand} " let "index = $index + 1" done



