21

Recently I put xset b off to my .bashrc. Now I'm annoyed by the error thet pops up when I log in via tty or via ssh, i.e. outside X session.

First thing that came in my mind was [[ -z "$SOME_VAR" ]] && xset b off (well, turns out that testing variable being set vs. being empty is a different question). But which SOME_VAR is the correct one?

So I diffed tty's set output and urxvt's set output to see which variables are set in X and missing in tty. As expected, there were quite many differences (listing only those that seemed relevant to me):

  • DESKTOP_SESSION
  • DISPLAY
  • GDMSESSION
  • SESSION_MANAGER
  • WINDOWID
  • WINDOWPATH
  • XAUTHORITY
  • XDG_SESSION_COOKIE
  • XDG_CONFIG_DIRS
  • XDG_DATA_DIRS
  • XDG_MENU_PREFIX

Which one is the most correct and universal one to test in order to detect if I'm in an X session or not? Something that would work across as many distros and platforms and desktop environments as possible?

Or is there even better way than testing environment variables?

Alois Mahdal
  • 4,440

6 Answers6

17

A simple and effective way to test that your display server is available and valid is to test it with xhost. You can't always rely on checking for a value in the DISPLAY variable since it could be set with an invalid value.

if xhost >& /dev/null ; then echo "Display exists"
else echo "Display invalid" ; fi

The reason I do this is because I run several scripts in my user crontab that operate on the display when it exists, but work differently when not. At the top of my crontab, I set the DISPLAY variable to :0 even though it doesn't exist yet. Scripts in the crontab that start with @reboot will start regardless of whether you have a display or not. This will allow you to dynamically detect when your display comes and goes within the same script.

NOTE: The >& only works in bash >= 4. Otherwise use > /dev/null 2>&1

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
cmevoli
  • 451
15

I think checking DISPLAY would be the best approach.

  • It handles remote logins (e.g. ssh -X).
  • It is available in most - if not all - platforms.
  • It is independent of window manager/DE.
Renan
  • 17,136
  • 2
    I'd also go for DISPLAY, or simply suppress the error message in general. Give /dev/null some love from time to time. – frostschutz Apr 11 '13 at 23:06
  • 4
    @frostschutz No, I'm trying to run only relevant part of script. Suppressing error messages does not make any step in that direction. In fact, it can lead to serious confusion troubleshooting other things that might potentially break. – Alois Mahdal Apr 14 '13 at 16:10
  • 1
    I started using this approach shortly after the answer, and it worked perfectly with simple sshs until now, when I started doing ssh -X---to be able to use Vim over ssh so that content selected by visual mode gets to local X clipboard, for which you don't need xserver on the server side. So DISPLAY gets set just as effect of simply enabling the forwarding, even if xserver and xset are not present. – Alois Mahdal Jul 10 '13 at 23:45
  • 1
  • 1
    Your DISPLAY variable can point to a display that doesn't actually have an X server running (for example when it is hardcoded in a script, or the X server was shut down after the variable was set). – n.st May 16 '19 at 07:06
6

I usually use the TERM variable to test for X in my scripts.

TERM is usually set to linux on TTY and xterm on X.
I use the word "usually" here, since applications like GNU Screen and TMux seem to mess with the TERM Variable.

darnir
  • 4,489
  • 1
    try echo $TERM to find out the richt setting on your mashine in different consoles. I use [ $TERM == "linux" ] && echo do some stuff on Ubuntu – rubo77 Sep 01 '15 at 06:17
3

This should work perfectly well:

[ ! -t 0 ] && xset b off                                  

http://tldp.org/LDP/abs/html/fto.html

-t

    file (descriptor) is associated with a terminal device

    This test option may be used to check whether the stdin [ -t 0 ] 
    or stdout [ -t 1 ] in a given script is a terminal.

So, when this evaluates to false ([ ! -t 0 ]) we are in a GUI environment.

terdon
  • 242,166
1

In an ordinary bash script: if [[ $DISPLAY ]]

On the same computer, $DISPLAY will return for example 0:0 in a terminal emulator, but nothing in a real terminal. This can easily be tested with CtrlAltF1 versus CtrlAltF7.

A bash condition based on $DISPLAY would look as follows:

if [[ $DISPLAY ]]; then 
  …
fi

In .profile or .personal: if xhost >& /dev/null

From my experience, $DISPLAY is not yet set when .profile, or by extension, .personal are executed. For those cases, the answer by user cmevoli serves best:

if xhost >& /dev/null; then
fi

I ran into this problem when defining a desktop CapsLock key mapping that should not apply to my server.

0

There are many ways you could do that.

In bash, try

function xruns {
    if [[ `pstree -As $$ | grep xinit | wc -l` == 1 ]]; then
        echo "You are in X."
    else
        echo "You are not in X."
    fi
}

Or, in zsh, try

#!/usr/bin/zsh

CURRENT_VT=`tty`

if [[ ${CURRENT_VT[6]} == "p" ]];        # or `${CURRENT_VT:5:1}` in bash
then
   # X stuff
else 
   # non-X stuff      
fi
Emanuel Berg
  • 6,903
  • 8
  • 44
  • 65
  • Point taken, but do you test your code before posting? The first one has syntax error and does not actualy detect if we are in X session so it will echo 1 if X is running and you log in via tty1-6 or ssh. The other one always does "non-X stuff"--I think that ${CURRENT_VT[6]} means rather 6th line than 6th char. – Alois Mahdal Apr 14 '13 at 16:22
  • @AloisMahdal: Aha, my stuff doesn't work in bash (I use zsh). Didn't think of that. Well, you could try it in zsh (type zsh) and possibly do some modifications if you like it, to make it work in bash. – Emanuel Berg Apr 14 '13 at 16:28
  • @AloisMahdal: OK, I changed it. As for the "log in via tty1-6", as it happens, that's what I do, and then I use the second solution (above) and set a variable. Check out this .zshrc and search for export VT. I use the variable to hold what Linux VT/console/tty I'm in (for the zsh prompt) but in X, I just set it to "X" (although not a VT). But that's details, you could work it out any way you'd like in bash using the same principle. – Emanuel Berg Apr 14 '13 at 16:59
  • I have added bash version of the condition to the second example. However, I think that the first one is still wrong. Maybe having ps print only ancestors would help. I'm not sure if it's possible, though. – Alois Mahdal Apr 14 '13 at 17:10
  • @AloisMahdal: Check out the edit. That does it for me, including the tty stuff. – Emanuel Berg Apr 14 '13 at 17:19