How to get the active tmux window's name? - vim

I want to write a script that gets the active tmux window's name and uses it as a variable for my vim session. Is this possible? I looked through the tmux manual and didn't see anything.

You can use display-message -p to query the name of the active window (among other things):
tmux display-message -p '#W'
If you want to target a specific window, you can use -t:
tmux -t «target-window» display-message -p '#W'
See the man page for the various ways to specify a target window (search for “target-window” in the Commands section).

SYNOPSIS
tmux [-28lquvVC] [-c shell-command] [-f file] [-L socket-name] [-S socket-path] [command [flags]]
SKIP
command [flags]
This specifies one of a set of commands used to control
tmux, as described in the following sections. If no commands are
specified, the new-session command is assumed.
You can find full list of tmux commands (two last arguments) in the manual, but now you interest is 'list-windows'.
tmux list-windows
0: zsh [156x40] [layout aebd,156x40,0,0,0] #0
1: mc [156x40] [layout aebe,156x40,0,0,1] #1 (active)
As you can see active window marked as '(active)'. This is what you were looking for?

First list all window names and active status, the active one will end with 1, then extract the name before it
tmux lsw -F '#{window_name}#{window_active}'|sed -n 's|^\(.*\)1$|\1|p'

Related

Start detached screen with ssh , without killing after the commands execute [duplicate]

I'm lazy, and I prefer that computers do my work for me. I ssh into several machines on a daily basis, so I created a simple script that launches some xterm windows and places them in positions I want (as you can see, I'm using bash):
#!/bin/bash
xterm -geometry 80x27+1930+0 &
xterm -geometry 80x27+2753+0 &
xterm -geometry 80x27+1930+626 &
xterm -geometry 80x27+2753+626 &
However, the next thing I do is go to the first window and type in
ssh server_a
then in the second
ssh server_b
and so on. What I'd like to do is have my script do the ssh commands in each xterm window, and then leave the windows open for me to do my work. I've seen the -e option for xterm, but the window closes after I execute my command. Is there a way to do this?
I apologize if this is a duplicate question. I've searched around and haven't had any luck with this. Many thanks!
I'd love to see a more elegant answer, but what I came up with does work:
xterm -e bash -c 'echo foo; exec bash'
Replace echo foo with the command of your choice, and you're good to go.
This answer gives one of the best answers I've seen so far to do this. Use the bash --init-file flag either in the shebang or when executing the terminal:
#!/bin/bash --init-file
commands to run
... and execute it as:
xterm -e /path/to/script
# or
gnome-terminal -e /path/to/script
# or
the-terminal -e bash --init-file /path/to/script/with/no/shebang
My only real complaint with the exec option is if the command executed prior to exec bash is long running and the user interrupts it (^C), it doesn't run the shell. With the --init-file option the shell continues running.
Another option is cmdtool from the OpenWin project:
/usr/openwin/bin/cmdtool -I 'commands; here'
# or
/usr/openwin/bin/cmdtool -I 'commands; here' /bin/bash
... where cmdtool injects the commands passed with -I to the slave process as though it was typed by the user. This has the effect of leaving the executed commands in the shell history.
Another option is to use gnome terminator. This creates and positions terminals interactively, and you can set up each terminal to run commands within terminator preferences.
Also does lots of extra tricks using keybindings for things like move, rotate, maximise/minimise of terminals within the containing terminator window
See: https://superuser.com/a/610048
"ClusterSSH controls a number of xterm windows via a single graphical console window to allow commands to be interactively run on multiple servers over an ssh connection"
https://github.com/duncs/clusterssh/wiki
$ cssh server_a server_b
$ command

How can I launch multiple xterm windows and run a command on each, leaving each window open afterward?

I'm lazy, and I prefer that computers do my work for me. I ssh into several machines on a daily basis, so I created a simple script that launches some xterm windows and places them in positions I want (as you can see, I'm using bash):
#!/bin/bash
xterm -geometry 80x27+1930+0 &
xterm -geometry 80x27+2753+0 &
xterm -geometry 80x27+1930+626 &
xterm -geometry 80x27+2753+626 &
However, the next thing I do is go to the first window and type in
ssh server_a
then in the second
ssh server_b
and so on. What I'd like to do is have my script do the ssh commands in each xterm window, and then leave the windows open for me to do my work. I've seen the -e option for xterm, but the window closes after I execute my command. Is there a way to do this?
I apologize if this is a duplicate question. I've searched around and haven't had any luck with this. Many thanks!
I'd love to see a more elegant answer, but what I came up with does work:
xterm -e bash -c 'echo foo; exec bash'
Replace echo foo with the command of your choice, and you're good to go.
This answer gives one of the best answers I've seen so far to do this. Use the bash --init-file flag either in the shebang or when executing the terminal:
#!/bin/bash --init-file
commands to run
... and execute it as:
xterm -e /path/to/script
# or
gnome-terminal -e /path/to/script
# or
the-terminal -e bash --init-file /path/to/script/with/no/shebang
My only real complaint with the exec option is if the command executed prior to exec bash is long running and the user interrupts it (^C), it doesn't run the shell. With the --init-file option the shell continues running.
Another option is cmdtool from the OpenWin project:
/usr/openwin/bin/cmdtool -I 'commands; here'
# or
/usr/openwin/bin/cmdtool -I 'commands; here' /bin/bash
... where cmdtool injects the commands passed with -I to the slave process as though it was typed by the user. This has the effect of leaving the executed commands in the shell history.
Another option is to use gnome terminator. This creates and positions terminals interactively, and you can set up each terminal to run commands within terminator preferences.
Also does lots of extra tricks using keybindings for things like move, rotate, maximise/minimise of terminals within the containing terminator window
See: https://superuser.com/a/610048
"ClusterSSH controls a number of xterm windows via a single graphical console window to allow commands to be interactively run on multiple servers over an ssh connection"
https://github.com/duncs/clusterssh/wiki
$ cssh server_a server_b
$ command

How do I change the starting directory of a tmux session?

The directory where a tmux session is started in will be the directory that new windows start at. How do I change this starting directory without closing the tmux session?
The way to do this is to detach from the session (^b d with the default keybindings) and then specify a different directory when you reattach to it. When attaching to a session, use the -c flag to specify the working directory. Here's an example:
$ tmux list-sessions
tmuxwtfbbq: 3 windows (created Tue Apr 5 14:25:48 2016) [190x49]
$ tmux attach-session -t tmuxwtfbbq -c /home/chuck/new_default_directory
This setting will be persisted - after you've reset the working directory, you won't need to keep specifying it every time you reattach to the session.
For the record, I'm on tmux version 2.0 (though I don't think it matters - I couldn't find anything about adding a -c option to the attach-session command in the change logs so I assume it's been there for quite a while).
Chucksmash's answer is a good one, but it can also be achieved without using the session if you like. The command attach-session is also available in the tmux command prompt; and the target session can be specified as the "current" session using a dot.
attach-session -t . -c /path/to/new/directory
Here's how you can change the tmux session's working directory without detaching the session, and without needing use to the <prefix> keystrokes:
(Option 1) Enter the directory at tmux command prompt:
tmux command-prompt "attach -c %1"
...will open a command prompt, then you type the working directory you want ~/my/dir and press ENTER
(Option 2) Provide the directory on the in-pane command line:
# Execute this in one of the shell panes of within your tmux session:
tmux command-prompt -I $PWD -P "New session dir:" "attach -c %1"
With this approach, the prompt for new-directory is pre-populated with the current dir of the pane which launched the command. Of course you can substitute anything else for $PWD if you please.
Want a shell function?
I have added this to my shell initialization:
# Change the current directory for a tmux session, which determines
# the starting dir for new windows/panes:
function tmux-cwd {
tmux command-prompt -I $PWD -P "New session dir:" "attach -c %1"
}
With all of these options, any future new windows will start in the given dir.
Note: attach, attach-session, and a are all aliases for each other. The tmux command-prompt has many other powers, it's worth reading the man page
use attach-session -c from command prompt or in a binding.
I have bindings to use the current directory automatically, using the provided pane_current_path var.
I have this bound to M-c, to update the current path.
# tmux.conf
# set default directory for new windows in this session to current directory:
bind M-c attach-session -c "#{pane_current_path}"
Similarly, when I just want another window in the current directory without changing the default, I have a binding on C:
# tmux.conf
# open a new window in the current directory
bind C new-window -c "#{pane_current_path}"
My bindings:
c: open a new window in session default directory [default binding]
C: open a new window in current directory
M-c: set session default directory to current directory
Happy Tmuxing!
The default working directory can be changed from the command line like this:
TMUX= tmux -C attach -c directory -t session </dev/null >/dev/null
Compared to command-prompt, for example, this has the advantage that no interactive prompts or confirmations are produced, so this can be run in a script. Unsetting TMUX allows attaching from inside a session, the option -C turns on control mode for non-interactive use and redirecting from /dev/null causes the client to detach immediately, while still updating the default directory. Redirecting the output is not necessary, but it suppresses messages.

Attach to 'screen' session with creating a new screen window

I have a screen session running with several windows. I want to attach to it, create a new screen window within it and start a shell in that new window.
Question: How can I do this from the command line outside the screen session?
I already tried a lot, e. g. screen -x (but it attaches to one of the existing screen windows; it does not create a new one nor does it start a new shell). Any hints are welcome.
Environment is Linux (Ubuntu 12.04).
Add new detached window to sesion_name and run command
screen -S sesion_name -x -X screen bash -c 'command; exec bash'
To choose a window to join, use the -p option. Giving + will create a new one, so your command is simply:
screen -x session_name -p +
This is documented on the man page:
-p n̲u̲m̲b̲e̲r̲_o̲r̲_n̲a̲m̲e̲|̲-̲|̲=̲|̲+̲
Preselect a window. This is useful when you want to reattach to a
specific windor or you want to send a command via the "-X" option
to a specific window. As with screen's select commant, "-" selects
the blank window. As a special case for reattach, "=" brings up the
windowlist on the blank window.
I found something on the mailing list, thank you tuxuday :)
I'm doing it now this way:
#!/bin/bash
screen -X screen -t NEWWINDOW # create new window (switches existing attached terminal)
sleep 0.1
screen -X other # switch existing attached terminal back to its old window
sleep 0.1
gnome-terminal -e 'screen -x -p NEWWINDOW' # connect to new window
I'm not sure about those sleeps, maybe they aren't necessary in all environments, but I can wait those 0.2s easily.
My .bash_aliases is changing the screen window title with a delay, so the awkward NEWWINDOW won't stick for long (and thus not hinder further calls to this script).

How can I tell whether I'm in a screen?

When using screen in linux, how can I tell if I'm in a screen or not?
I could do exit and I'll exit a screen if I was in one, but if I wasn't, then I'll end up closing my terminal.
When doing screen -r, I could see if I have other screens attached, but how do I know if my current terminal is one of those attached screens?
Check $STY. If it's null, you're on a "real" terminal. If it contains anything, it's the name of the screen you're in.
If you are not in screen:
eric#dev ~ $ echo $STY
eric#dev ~ $
If you are in screen:
eric#dev ~ $ echo $STY
2026.pts-0.ip-10-0-1-71
Another way I've done it is to echo $TERM.
$ echo $TERM
screen
Since I end up doing this a lot, I added an alias into my .bashrc file:
alias trm='echo $TERM'
This way, whether in screen or not, if I just execute 'trm' it will show me whether I'm in SCREEN or elsewhere (usually XTERM).
Alternative approach to check if you are in screen.
type:
Ctrl-a ?
If you see the screen help you are in screen.
Otherwise you'll get a question mark '?' on the prompt.
Since all of the other methods here rely on environment variables (which can simply be overridden) or the command character for screen (which can also be overridden), the most foolproof way to check would be to list all the ancestors of the current process.
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | grep screen | wc -l
If it prints 1, then the current process you're running has an ancestor with the word 'screen' in the executable's name, otherwise there wasn't.
A more facile visible inspection might be obtained from:
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | less
My solution to the problem is a lot simpler: just hitting TAB makes the full terminal blink (a quick video inversion) if you are inside GNU Screen.
Tested working on most Linux (Ubuntu, Kali, Debian, RaspBerry... etc) and FreeBSD, GUI and any terminal, local or remote, including CtrlAltFn ones.
As an exception for this method, please, note this (rather complex, but possible) case scenario:
1.- SSH into computer A (lets assume Linux).
2.- Enter a new screen -S AScr from remote terminal on computer A.
3.- SSH from GNU Screen AScr terminal into Computer B.
4.- Enter a new screen -S BScr from remote terminal on computer B.
You are inside a Screen on cases 2 and 4, and outside a Screen on cases 1 and 3, but the terminal will blink on cases 2, 3 and 4.
While ssh'd into a remote (older) system I noticed that $TERM indicated I was using 'screen-256color', however there was no termcap/terminfo entry for that, so I was forced to resort to the following in .bashrc to prevent the terminal from producing occasional garbage:
case $TERM in
(screen-256color) export TERM='screen'
esac
to get it to use the plain entry instead.
TL;DR, $TERM will usually indicate if you are in a screen session when ssh'd remotely. You can use case $TERM in (screen*) echo "you are in a screen session"; esac if you just want a visual clue and don't need to do something specific
Add one or more of the followings into your .bashrc
alias mysession='echo ${STY}'
alias myterm='echo ${TERM}'
alias isscreen='if test -n "$STY"; then echo " screen session: ${STY}"; else echo " NOT a screen session"; fi'
Then you can know if you are inside a screen by typing simple commands.
The problem with most of the above answers is that we might be in a subshell of an attached screen session. Or we might be opening a shell to a remote host from within a screen session. In the former case, we can walk the process tree parentage and match for the screen program name. In the latter case, most of the time, we can check the TERM variable for something like screen*.
My answer os similar to /u/Parthian-Shot but not so dependent on the pstree utility; the options he use are not available to me. On the other hand, my implementation is still Linux-dependent: for non-Linux systems, one must tweak the ps command; for systems with older shells that don't support arrays, you'll have yet more work-arounds. But anyway:
ps_walk_parents() {
local tmp
local ppid=$PPID
while [[ $ppid != 1 ]]; do
tmp=($( ps -o ppid,comm -p $ppid ))
ppid=${tmp[0]} # grab parent pid
echo ${tmp[1]} # output corresponding command name
done
}
if [[ "$TERM" =~ screen* ]] || ps_walk_parents |grep -qxi screen ; then
# we are in a screen terminal
fi
We could optimize our function a bit to stop searching if/when a process parent matches the target command name ("screen"), but in general, the function will only hit 2 to 3 iterations. Presumably you want to put this code in some startup initialization such as .bashrc or .profile or something, so again, not worth optimizing.
screen -ls can tell you.
Outside screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Detached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.
Inside a screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Attached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.

Resources