>    I have followed the advice Brian gave here, and I can set this up easily
>    on my own system. Yet, when I start a terminal session, ssh to another
>    host from where I start screen, this solution with preexec doesn't work.
>    I have copied my (working) .bashrc, .screenrc and preeexec.bash over to
>    the remote system, so the files are identical, but as to why this wont
>    work is eluding me. How can the fact that i come from a remote host, with
>    the same setting, be in the way of sending the dynamic title? Can any one
>    shed some light on this?
> 
>    Leen
> 
>    I have the following in my bashrc:
>    . ./preeexec.bash
>    set_xterm_title () {
>        local title="$1"
>        case "$TERM" in
>        xterm*|rxvt*)
>            echo -ne "\e]0;$title\007"
>            ;;
>        screen)
>            echo -ne "\033k$title\033\\"
>            ;;
>        esac
>    }
>    precmd () {
>        set_xterm_title "${us...@${hostname} `dirs -0` $PROMPTCHAR"
>    }
> 
>    preexec () {
>        set_xterm_title "${us...@${hostname}"
>    }
>    preexec_install
> 
>    And in my screenrc:
>            setenv SCREEN_RUN_HOST $SCREEN_HOST
>            setenv SCREEN_RUN_USER $USER
>            setenv LC_SCREEN_RUN_HOST $SCREEN_HOST
>            setenv LC_SCREEN_RUN_USER $USER

Sorry for the delayed response.  I'm guessing that SCREEN_HOST isn't
set.  

To hopefully simplify things I've attached a set of stripped down files
from my own setup including a basic .bashrc, .bash.preexec, .screenrc,
and .ssh/config all complete with comments and links.  Hopefully the
formatting doesn't get all screwed up.  If it does I can attach a
tarball, but I think that's generally against mailing list etiquette.

The .bash.preexec is fairly different from the one that was originally
posted.  It includes functions to rename a running screen session, turn
on/off dynamic window naming and force a particular name, history files
with timestamps, and some different formatting.  

I'd suggest you dump them into a test user's environment for playing
with and then take the bits that you like and put them in your own.

Also, these things should probably be on the remote host as well.  Most
of the hosts I logon to are managed by cfengine and for the rest I have
a simple rsync script to put a copy there.  Something like svn would
probably also work.

Cheers,
Brian
# .bashrc
# 2009-06-17
# bpkroth
#
# This is a stripped down copy of my current .bashrc file for the purposes of
# showing how I use bash, preexec, and screen to display more meaningful
# information in ssh sessions.  My usual set of rc files is used in several
# different environments so a few of the extra bits of error checking and
# strange syntax are left in here.  And yes all of these comments usually exist
# because I expect myself to forget what things are for otherwise.

# exit if this is not an interactive shell
if [ -z "$PS1" ]; then
        return
fi

function bin_in_path { 
        local out=""
        if ! out=`which $1 2>&1` || echo "$out" | egrep "^no $1 in " > 
/dev/null; then 
                return 1
        else 
                return 0
        fi
}

# Turn the screen session name into something a little bit easier to read.
# This will be used by .bash.preexec later.
case $TERM in
        screen*)
                if [ -z "$LC_MYSTY" ] && [ -n "$STY" ]; then
                        export LC_MYSTY=`echo $STY | awk -F. '( NF == 2 ) { 
print $2 } ( NF == 3 ) { print $2 FS $3 }'`
                fi
                ;;
esac

# Some tweaks for su/sudo customization
export MYUSER=bpkroth
if [ $EUID == 0 ]; then
        export MYCONFDIR=~bpkroth
        export PATH=/root/bin:$PATH
        unset DISPLAY
        umask 0022
else
        export MYCONFDIR=~bpkroth
        export USERNAME=$USER
        umask 0026

        # Auto launch screen on SSH connections
        # Sometimes a pain to deal with SSH screen sessions.
        # Can be done with C-a a* though.
        # Also a good idea to always use a hardstatus or caption line in 
.screenrc
        if ! [[ $TERM == screen* ]] && bin_in_path screen; then
                if [ -n "$SSH_TTY" ]; then
                        # This is a remote session.
                        # Connect to the singular screen instance if it is
                        # available, else list if there are multiple, else
                        # start a new one.
                        N=`screen -list | grep -c '[0-9].*tached'`
                        if [ $N == 1 ]; then
                                sleep .5 && screen -X windowlist -b &
                                #exec screen -x -p -
                                screen -x -p -
                        elif [ $N == 0 ]; then
                                #exec screen
                                screen
                        else
                                echo
                                screen -list
                        fi
                #else # local connection, don't open a screen session by default
                #       screen
                fi
        fi
fi

MYTTY=`tty 2>&1`

# Force use of my screenrc file, even if I'm being lazy and "sudo screen".
export SCREENRC=$MYCONFDIR/.screenrc

# Add a timestamp to history records.
export HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S:: '

# Install ZSH style precmd() and preexec() functions.
# Useful for setting the title of the terminal to the command that's
# running, not just which directory in.  This make distinguishing
# screen sessions much easier as well.
if echo "$MYTTY" | grep '/dev/pts' > /dev/null || echo "$MYTTY" | grep 
'/dev/tty' > /dev/null; then
        if [ -f $MYCONFDIR/.bash.preexec ]; then
                # Note: This requires NOT using DEBUG or PROMPT_COMMAND.  It
                #       should also be the last thing we do in the bashrc.

                unset PROMPT_COMMAND
                
                # The script works better if these variables are set.
                # http://glyf.livejournal.com/63106.html?thread=210818
                export SCREEN_HOST=$HOSTNAME

                # If this is a local connection, also try to set some env
                # variables that may or may not be transferred to other hosts.
                # See also: 
                # man sshd_config       AcceptEnv
                # man ssh_config        SendEnv
                if [ -z "$SSH_TTY" ]; then
                        [ -z "$LC_HOST" ] && export LC_HOST=$HOSTNAME
                        [ -z "$LC_USER" ] && export LC_USER=$USER
                fi

                if [ $EUID == 0 ]; then
                        export PROMPTCHAR='#'
                else
                        export PROMPTCHAR='$'
                fi

                . $MYCONFDIR/.bash.preexec

                # The built in functions script pretty much do what I want them 
to.
                # I just tweaked the format a little.
                preexec_xterm_title_install
        fi
fi

# Some environment cleanup
unset MYTTY
#!/bin/bash
# bash.preeexec
# 2009-01-25
# bpkroth
#
# This script was originally obtained from here:
# http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
# 
# I modified the display format slightly and allowed for history with
# timestamps.  I also provided some extra functions at the bottom for renaming
# the screen sessions and windows.  It also requires some tweaks to .screenrc
# and .bashrc.  Please see the following:
# http://glyf.livejournal.com/63106.html?thread=210818

# preexec.bash -- Bash support for ZSH-like 'preexec' and 'precmd' functions.

# The 'preexec' function is executed before each interactive command is
# executed, with the interactive command as its argument.  The 'precmd'
# function is executed before each prompt is displayed.

# To use, in order:

#  1. source this file
#  2. define 'preexec' and/or 'precmd' functions (AFTER sourcing this file),
#  3. as near as possible to the end of your shell setup, run 'preexec_install'
#     to kick everything off.

# Note: this module requires 2 bash features which you must not otherwise be
# using: the "DEBUG" trap, and the "PROMPT_COMMAND" variable.  preexec_install
# will override these and if you override one or the other this _will_ break.

# This is known to support bash3, as well as *mostly* support bash2.05b.  It
# has been tested with the default shells on MacOS X 10.4 "Tiger", Ubuntu 5.10
# "Breezy Badger", Ubuntu 6.06 "Dapper Drake", and Ubuntu 6.10 "Edgy Eft".


# Copy screen-run variables from the remote host, if they're available.

if [[ "$SCREEN_RUN_HOST" == "" ]]
then
        SCREEN_RUN_HOST="$LC_SCREEN_RUN_HOST"
        SCREEN_RUN_USER="$LC_SCREEN_RUN_USER"
fi

# This variable describes whether we are currently in "interactive mode";
# i.e. whether this shell has just executed a prompt and is waiting for user
# input.  It documents whether the current command invoked by the trace hook is
# run interactively by the user; it's set immediately after the prompt hook,
# and unset as soon as the trace hook is run.
preexec_interactive_mode=""

# Default do-nothing implementation of preexec.
function preexec () {
        true
}

# Default do-nothing implementation of precmd.
function precmd () {
        true
}

# This function is installed as the PROMPT_COMMAND; it is invoked before each
# interactive prompt display.  It sets a variable to indicate that the prompt
# was just displayed, to allow the DEBUG trap, below, to know that the next
# command is likely interactive.
function preexec_invoke_cmd () {
        precmd
        preexec_interactive_mode="yes"
}

# This function is installed as the DEBUG trap.  It is invoked before each
# interactive prompt display.  Its purpose is to inspect the current
# environment to attempt to detect if the current command is being invoked
# interactively, and invoke 'preexec' if so.
function preexec_invoke_exec () {
        if [[ -n "$COMP_LINE" ]]
        then
                # We're in the middle of a completer.  This obviously can't be
                # an interactively issued command.
                return
        fi
        if [[ -z "$preexec_interactive_mode" ]]
        then
                # We're doing something related to displaying the prompt.  Let 
the
                # prompt set the title instead of me.
                return
        else
                # If we're in a subshell, then the prompt won't be re-displayed 
to put
                # us back into interactive mode, so let's not set the variable 
back.
                # In other words, if you have a subshell like
                #   (sleep 1; sleep 2)
                # You want to see the 'sleep 2' as a set_command_title as well.
                if [[ 0 -eq "$BASH_SUBSHELL" ]]
                then
                        preexec_interactive_mode=""
                fi
        fi
        if [[ "preexec_invoke_cmd" == "$BASH_COMMAND" ]]
        then
                # Sadly, there's no cleaner way to detect two prompts being 
displayed
                # one after another.  This makes it important that 
PROMPT_COMMAND
                # remain set _exactly_ as below in preexec_install.  Let's 
switch back
                # out of interactive mode and not trace any of the commands run 
in
                # precmd.

                # Given their buggy interaction between BASH_COMMAND and debug 
traps,
                # versions of bash prior to 3.1 can't detect this at all.
                preexec_interactive_mode=""
                return
        fi
        if [[ "$BASH_SUBSHELL" -gt 0 ]]; then
                # Without this things like the following get really angry due
                # to the subshell:
                # for i in `seq 1 3`; echo $i; done
                return
        fi

        # In more recent versions of bash, this could be set via the 
"BASH_COMMAND"
        # variable, but using history here is better in some ways: for example, 
"ps
        # auxf | less" will show up with both sides of the pipe if we use 
history,
        # but only as "ps auxf" if not.
        local this_command=`history 1 | sed -e 's/^[ ]*[0-9]*[ 
]*[0-9]*[-]*[0-9]*[-]*[0-9]*[ ]*[0-9]*[:]*[0-9]*[:]*[0-9]*[:]*[ ]*//g'`;

        # If none of the previous checks have earlied out of this function, then
        # the command is in fact interactive and we should invoke the user's
        # preexec hook with the running command as an argument.
        preexec "$this_command"
}

# Execute this to set up preexec and precmd execution.
function preexec_install () {

        # *BOTH* of these options need to be set for the DEBUG trap to be 
invoked
        # in ( ) subshells.  This smells like a bug in bash to me.  The null 
stderr
        # redirections are to quiet errors on bash2.05 (i.e. OSX's default 
shell)
        # where the options can't be set, and it's impossible to inherit the 
trap
        # into subshells.

        set -o functrace > /dev/null 2>&1
        shopt -s extdebug > /dev/null 2>&1

        # Finally, install the actual traps.
        PROMPT_COMMAND=preexec_invoke_cmd
        trap 'preexec_invoke_exec' DEBUG
}

# Since this is the reason that 99% of everybody is going to bother with a
# pre-exec hook anyway, we'll include it in this module.

# Change the title of the xterm.
function preexec_xterm_title () {
        if [ -n "$MYTITLE" ]; then
                printf '\e]0;%s\007' "$MYTITLE"
        else
                #echo -ne "\e]0;$1\007"
                printf '\e]0;%s\007' "$1"
        fi
}

function preexec_screen_title () {
        # Allow for manual SCREEN_TITLE's
        if [ -n "$MYTITLE" ]; then
                printf '\ek%s\e\\' "$MYTITLE"
        else
                #echo -ne "\ek$1\e\\"
                printf '\ek%s\e\\' "$1"
        fi
} 

# Abbreviate the "u...@host" string as much as possible to preserve space in
# screen titles.  Elide the host if the host is the same, elide the user if the
# user is the same.
function preexec_screen_user_at_host () {
        local RESULT=""
        if [[ "$SCREEN_RUN_USER" != "$USER" ]]
        then
                RESULT="${USER}"
        fi

        if [[ "$SCREEN_RUN_HOST" != "$SCREEN_HOST" ]]
        then
                RESULT="${resu...@${screen_host}:"
        elif [[ -n "$RESULT" ]]
        then
                RESULT="${RESULT}@:"
        fi

        echo -n "$RESULT"
}

# Similar to the function above that uses some extra variables available
# through the use of .screenrc, except that this one can't do that with out
# root having configured the remote SSH to accept LC_* variables.  Instead we
# just explicitly get rid of my username (bpkroth).
function preexec_user_at_host () {
        local RESULT=""
        if [[ "$LC_USER" != "$USER" ]]
        #|| [[ "$USER" != "$MYUSER" ]]
        then
                RESULT="${USER}"
        fi

        if [[ "$LC_HOST" != "$SCREEN_HOST" ]]
        then
                RESULT="${resu...@${screen_host}:"
        elif [[ -n "$RESULT" ]]
        then
                RESULT="${RESULT}@:"
        fi

        echo -n "$RESULT"
}

# Abbreviate the TERM a bit
function preexec_term () {
        case "$TERM" in
                rxvt-unicode)
                        echo "urxvt"
                        ;;
                screen*)
                        if [[ -n "$LC_MYSTY" ]]; then
                                echo "S[$LC_MYSTY]"
                        else
                                echo "$TERM"
                        fi
                        ;;
                *)
                        echo "$TERM"
                        ;;
        esac
}

function preexec_xterm_title_install () {
        # These functions are defined here because they only make sense with the
        # preexec_install below.
        function precmd () {
                local dir=`dirs -0`
                if [[ "$TERM" != linux ]]; then
                        preexec_xterm_title "`preexec_term` - 
`preexec_user_at_host`$dir $PROMPTCHAR"
                fi
                if [[ "$TERM" == screen ]] || [[ "$TERM" == screen.linux ]]
                then
                        preexec_screen_title "`preexec_screen_user_at_host`$dir 
$PROMPTCHAR"
                fi
        }

        function preexec () {
                #[ -z "$1" ] && return
                local dir=`dirs -0`
                if [[ "$TERM" != linux ]]; then
                        preexec_xterm_title "`preexec_term` - 
`preexec_user_at_host`$dir $PROMPTCHAR $1"
                fi
                if [[ "$TERM" == screen ]] || [[ "$TERM" == screen.linux ]]
                then
                        #echo "preexec: $1"
                        preexec_screen_title "`preexec_screen_user_at_host`$dir 
$PROMPTCHAR $1"
                        return
                        # Not sure if we actually need this stuff below.

                        local cutit="$1"
                        local cmdtitle=`echo "$cutit" | cut -d " " -f 1`
                        local args=""
                        if [[ "$cmdtitle" == "exec" ]]
                        then
                                local cmdtitle=`echo "$cutit" | cut -d " " -f 2`
                        fi
                        if [[ "$cmdtitle" == "screen" ]]
                        then
                                # Since stacked screens are quite common, it 
would be nice to
                                # just display them as '$$'.
                                local cmdtitle="$PROMPTCHAR"
                        else
                                # Get the args, but trim them so the caption in 
the screen is still ledgible.
                                # We also need to escape certain characters for 
sed's sake.
                                local escapedcmdtitle=`echo $cmdtitle | sed 
's/\//\\\\\//g'`
                                escapedcmdtitle=`echo "$escapedcmdtitle" | sed 
's/\[/\\\\[/g'`
                                local args=`echo "$cutit" | sed -e "s/^exec[ 
]*//" -e "s/^${escapedcmdtitle}[ ]*//" -e 's/^\(.\{20\}\).*/\1.../'`
                                local cmdtitle="$PROMPTCHAR $cmdtitle $args"
                        fi
                        preexec_screen_title "`preexec_screen_user_at_host`$dir 
$cmdtitle"
                fi
        }

        preexec_install
}

# A function to allow forcing a manual static window title.
function set_window_title () {
        [ -n "$1" ] && export MYTITLE="$1"
}
alias setwindowtitle=set_window_title

# And to go back to dynamic window titles.
function unset_window_title () {
        unset MYTITLE
}
alias unsetwindowtitle=unset_window_title

# This function sends a rename command to both the .bash.preexec functions and
# the local screen session.  It is not capable of renaming all windows since
# they may not all be at the command prompt.
function rename-screen() {
        NAME="$1"
        if [ -z "$1" ]; then
                echo "Usage: rename-screen <new screen name>"
                return
        fi
        
        if [ -z "$STY" ] || ( ! [ "$TERM" == "screen" ] || [ "$TERM" == 
"screen.linux" ] ); then
                echo "ERROR:  This command can only be used inside a local 
screen session!" >&2
                return
        fi

        SPID=`echo $STY | sed "s/$LC_MYSTY$//"`

        screen -X sessionname "$NAME"

        export STY="$SPID$NAME"
        export LC_MYSTY="$NAME"

        # *If* we could get a list of the windows that this session has then we
        # could use the following to send the commands to update the env
        # everywhere.  Note, that this still poses problems with windows that
        # are ssh'd elsewhere.

        for window in $windowlist; do
                if echo "$window" | grep -q '\$\s*$'; then
                        id=`echo "$window" | awk '{ print $1 }'`
                        screen -X at $id stuff "export STY='$SPID$NAME'; 
LC_MYSTY='$NAME'
                        "
                fi
        done
}
# .screenrc
# 2009-06-17
# bpkroth
#
# This is a stripped down version of my usual screenrc file for purposes of
# demonstrating how to use bash, preexec, screen, ssh goodies.

# Add a caption at the bottom of the screen session that shows the list of
# windows, hostname, date, and time.
#
# original, results in nasty whiteness and no trunc with too many windows
#caption always "%{= .w}%-w%{=b .c}%n %t%{-}%+w %-= @%H - %l - %D %d %M - %c"
#caption always "%{= .w}%-w%{=b .c}%-81<%n %t%{-}%+w%<%-048= @%H - %l - %D %d 
%M - %c"
# truncates in the middle
#caption always "%L>%{= .w}%-Lw%{=b .c}%-85<%n%f %t%{-}%-049L<%+Lw%-049= @%H - 
%l - %D %d %M - %c"
# ... on both ends, but sometimes truncs the active window
#caption always "%{= .w}%-w%L>%{=b .c}%n %t%{-}%+w %-48= @%H - %l - %D %d %M - 
%c"
#
# This adds a statusbar:
# - windows and their flags before the active one are listed in white and 
truncated with ...
# - the active window and it's flags are in bold cyan and aligned slightly to 
the left 
# - the rest of the windows are printed and truncated so that
# - a string describing the current machine, load, and date/time are right 
aligned
caption always "%{= .w}%-Lw%20L>%{=b .c}%n%f %t%{-}%+Lw %-048= @%H - %l - %D %d 
%M - %c"

defhstatus "screen @ H - n t"
hardstatus off

# Update utmp by default so we can see what's up in "w".
deflogin on

# Export a variable denoting the original host screen was started on.
# This is used by the bash.preexec stuff:
# http://glyf.livejournal.com/63106.html?thread=210818
setenv SCREEN_RUN_HOST $SCREEN_HOST
setenv SCREEN_RUN_USER $USER
setenv LC_SCREEN_RUN_HOST $SCREEN_HOST
setenv LC_SCREEN_RUN_USER $USER
# ssh_config
# 2009-06-17
# bpkroth
#
# This is a stripped down version of my usual ssh_config file for the purposes
# of showing how to use the ssh, bash, preexec, screen goodies.

# This attempts to send whatever LC_* environment variables you've set to the
# remote host.
Host *
        SendEnv LC_*
_______________________________________________
screen-users mailing list
screen-users@gnu.org
http://lists.gnu.org/mailman/listinfo/screen-users

Reply via email to