Base16 colors break under tmux ssh - ssh

I'm using the same dot files for all my machines.
On my local machine everything works just fine in tmux, when sshing over to
one of my machines the colors breaks. Colors also work sshing in general outside of tmux.
General settings can be seen in the image

Since there is not tmux session running on the remote host (tmux running locally with ssh happening in one of the panes), there is no $TMUX environment variable set.
Base16 script expects there to be such a flag for RGBs to be properly set
if [ -n "$TMUX" ]; then
# Tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
put_template() { printf '\033Ptmux;\033\033]4;%d;rgb:%s\033\033\\\033\\' $#; }
put_template_var() { printf '\033Ptmux;\033\033]%d;rgb:%s\033\033\\\033\\' $#; }
put_template_custom() { printf '\033Ptmux;\033\033]%s%s\033\033\\\033\\' $#; }
elif [ "${TERM%%[-.]*}" = "screen" ]; then
...
Workaround is currently to fix the if statement in each script.

Related

How do I change the color for directories with ls using tmux?

I am using a bash function to change the foreground and background color of tmux pane if I am in a dev or prod remote server.
.bash_profile
function sshTmuxColor() {
if [ -n "$TMUX" ]; then
case "$1" in
prod_*)
tmux selectp -P 'fg=white,bg=colour52' #colour124=darker-red
;;
dev_*)
tmux selectp -P 'fg=white,bg=colour22' # color28=darker-green
;;
esac
fi
ssh "$#"
tmux selectp -P default
}
alias ssh=sshTmuxColor
Is it possible to change the color of directories on the remote server when I use ls? Or am I better of optimizing my colors for whatever the color of remote directories are? (Changing them is not really an option). This is a follow up to this question.

Cygwin ssh not setting DISPLAY correctly (extra :0)

I am using Cygwin on Windows 7 to connect to a unix (RHEL 6) server via SSH. When I do so, X forwarding is not being set correctly:
(Starting from Cygwin xterm on the Windows machine)
> echo $DISPLAY
:0
> ssh -Y myname#rhel.server.com
[enter password]
> echo $DISPLAY
localhost:52.0:0
If I now try to start any windowed process, I get an error message:
> emacs
emacs: Cannot connect to X server localhost:52.0:0.
Check the DISPLAY environment variable or use '-d'.
Also use the 'xhost' program to verify that it is set to permit connections from your machine.
Additional Details
The number that follows 'localhost' (52 in the example above) is different each time I connect.
If I do the following,
> export DISPLAY=localhost:52.0
(that is, I remove the trailing ":0) then this DOES fix the issue, and the window forwarding works just fine.
So the question is: how to fix so that I do not need to manually change the DISPLAY variable with each connection?
A false alarm, much to my embarrassment. Turns out my .profile (that I had borrowed from someone else, as it contained a large quantity of useful customization for our development environment) contained these lines:
export DISPLAY
if [[ -z $DISPLAY ]]; then
DISPLAY=my.machine.addr:0
elif echo $DISPLAY | grep -z -v ':0'; then
DISPLAY=$DISPLAY:0
fi
Lo and behold, commenting out the elif branch solves the problem. May this be a lesson to us all on the dangers of copying someone else's config without knowing what it contains.

Auto attach to gnu screen on remote host (ssh) only

So I distribute my dotfiles on all my machines. I want to put something like the following in my .zshrc
# Autoload screen if we aren't in it.
if [[ $STY = '' ]] then screen -xR; fi
Which I got from What's in your .zshrc?
But I only want to attach to screen when I ssh to remote hosts... not if I'm on my local machine. Is there an environment variable I can test to see if this is an SSH session or localhost console?
Right now I'm going to test the $SSH_TTY variable which seems to be reliable from the few hosts I've tried:
if [[ $STY = '' && $SSH_TTY != '' ]] then screen -xR; fi

rsync exits with the message "stdin is not a tty"

I want to use rsync to my remote server for which I have SSH access. I use the following command:
rsync -e 'ssh -p 22222' -rtz --delete content_dir/ user#example.com:/home/user/public_html
After entering the command, it asks for the password for the remote location. When I type it, it exits with the message,
stdin: is not a tty
How do I supply the password to rsync? The method suggested should also work when I use it in a shell script.
You need to add:
[ -z "$PS1" ] && return
to the beginig of .bashrc that is located in your home dir.
The password is being accepted here, as you've stated yourself the operation does happen.
The error message "stdin: is not a tty" is due to something in the startup script on your server attempting to process an action that should only happen for interactive logins (when you connect with ssh direct to the server, etc).
[ -z "$PS1" ] && return solves the problem but it checks whether the prompt string length equals to zero and if it does then exits. Although $PS1 will not be set in a non-interactive shell, $PS1 being of zero length doesn't ultimately mean that the shell is not interactive.
Better approach is to check the shell's current options using $-. For example [[ $- != *i* ]] && return.
In case a simple return doesn't do the job, here's another approach taken from this blog article:
if `tty -s`; then
mesg n
fi
tty -s checks if there's a TTY attached (the -s tells it to do so silently and just exit with the appropriate return code). tty returns the tty attached (e.g. "/dev/pts/1"). This should be safer than checking some shell variable ;)
mesg controls the write access to your terminal (msg n disallows writing to the (in our case non-existing) terminal), and thus requires one to be present.
On some systems (in my case Debian Jessie, but there are also reports on Ubuntu) mesg n1 is set unconditionally in either ~/.bashrc or ~/.profile. So if it exists that way, this might be the culprit.
As with the other examples, you can of course make that a one-liner: [[ $(tty -s ) ]] && mesg n. And nobody keeps you from combining the two:
if [[ $(tty -s ) ]]; then
mesg n
else
return
fi
Btw: According to the linked article, this fragment should go to the .bashrc of the machine you connect to (the "remote") – so if that's johndoe#somehost, this should be applied at the start of /home/johndoe/.bashrc on somehost. In my case I only got rid of the message after having applied this change on the "calling host" as well.
PS: Also check the .profile if it has a stand-alone msg n command (it did in my case). If it does, wrap it there.
1: mesg n is used to prevent other users on the machine writing to your current terminal device, which per se is a good thing – but not helpful for some rsync job ;)

Automatically (or more easily) reconnect to a screen session after network interruption

ADDED: This question is now, I believe, subsumed by this one:
Using GNU Screen completely transparently and automatically
See also this related question:
https://superuser.com/questions/147873/ssh-sessions-in-xterms-freeze-for-many-minutes-whenever-they-disconnect
Original question:
It would be nice if there were a way to ssh to a machine and immediately reconnect to a specific screen session. You can do this:
laptop> ssh server.com screen -ls
and it will show a list of screens available on server.com like so [1]:
123.pts-1
456.pts-2
And then you might try to do this:
laptop> ssh server.com screen -dr pts-2
but that fails, saying "Must be connected to a terminal."
You have to ssh in first and then do the "screen -dr pts-2" on server.com which is no good if you have a flaky connection and get disconnected a lot. You want to be able to resume with a simple "up-arrow enter" on the laptop. (Or perhaps make it even more automatic.)
I have a rihackulous solution to this problem which I'll post as an answer and hope it gets downvoted to oblivion in favor of the Right Way to deal with this.
Footnotes:
[1] Or, better, if you created the screen sessions with names like "screen -S foo" and "screen -S bar" then you'll get a friendlier list like:
123.foo
456.bar
and can reconnect with, eg, "screen -dr foo".
Mini screen tutorial, incorporating the answer to this question:
Login in to server.com and do
screen -S foo
and then never log out of that session again.
To reconnect to it from elsewhere, do
ssh -t server.com screen -dr foo
To list available screens to reconect to:
screen -ls
or, of course,
ssh server.com screen -ls
to check on server.com's available screens remotely.
I now use the following alias (tcsh), based on Jason's answer below, to connect to a named screen if it exists or create and connect otherwise:
alias ssc 'ssh -t \!:1 "screen -S \!:2 -dr || screen -S \!:2"'
Does the -t option do what you want?
-t Force pseudo-tty allocation. This can be used to execute arbi-
trary screen-based programs on a remote machine, which can be
very useful, e.g. when implementing menu services. Multiple -t
options force tty allocation, even if ssh has no local tty.
So:
laptop> ssh -t server.com screen -dr pts-2
This seems to work in my installation.
This is now subsumed by this: Using GNU Screen completely transparently and automatically
Here's a script, ssc, that works just like ssh but takes a third argument to specify the screen to reconnect to, or the name of a new screen.
I believe this script subsumes everything in the original question.
#!/usr/bin/env perl
# Use 'ssc' (this script) instead of 'ssh' to log into a remote machine.
# Without a 3rd argument it will list available screens.
# Give it a 3rd argument to attach to an existing screen or specify a new
# screen. Eg, ssc remote.com foo
# The numbers in front of the screen tag can usually be ignored.
# Screen is a little too clever though in that if there's an existing screen "bar"
# and you say "ssc remote.com b" it will reconnect you to "bar" instead of making
# a new screen "b". It's like invisible and silent tab-completion.
if(scalar(#ARGV)==0 || scalar(#ARGV) > 2) {
print "USAGE: ssc remote.com [screen name]\n";
} elsif (scalar(#ARGV) == 1) {
$machine = shift;
#screens = split("\n", `ssh $machine screen -ls`);
for(#screens) {
if(/^\s*(\d+)\.(\S+)\s+\(([^\)]*)\)/) {
($num, $tag, $status) = ($1, $2, $3);
if($status =~ /attached/i) { $att{"$num.$tag"} = 1; }
elsif($status =~ /detached/i) { $att{"$num.$tag"} = 0; }
else { print "Couldn't parse this: $_\n"; }
}
}
print "ATTACHED screens:\n";
for(keys(%att)) { print " $_\n" if $att{$_}; }
print "DETACHED screens:\n";
for(keys(%att)) { print " $_\n" unless $att{$_}; }
} else {
$machine = shift;
$tag = shift;
system("ssh -t $machine \"screen -S $tag -dr || screen -S $tag\"");
}
Use the -t option to ssh to allocate a terminal while directly running a command.
laptop> ssh -t server.com screen -dr pts-2
I've been working on something similar but not quite got there, your solutions have solved my problem so here's my suggestion:
ssh -t server.com "screen -S foo -rd || screen -S foo"
This just tries to open the existing screen named foo and if it doesnt exist, creates it.
I'll put this in a launcher on my laptop, so when the wireless network goes I can just open where I left off.
Just noticed that the default screen shell is a bit weak, so an improvement which sets up your home environment a little better is:
ssh -t server.com "screen -S foo -rd || screen -S foo bash -l"
I converted this to work on OS X .bash_profile with one addition: If no 2nd parameter is given, it will start a session "default".
function ssc() {
if [[ -z $2 ]]; then
screen="default"
else
screen=$2
fi
ssh -t $1 "screen -S $screen -dr || screen -S $screen"
}
If you like to connect to the same session always even it is active, detached or not exists yet:
ssh -t user#server screen -xR screenName
The same but create a new session if it is already active on some other pty:
ssh -t user#server screen -rR screenName