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,330
  • 11
  • 40
  • 62

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
  • 55,929
  • 26
  • 146
  • 227
cmevoli
  • 451
  • 4
  • 4
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
  • 16,976
  • 8
  • 69
  • 88
  • 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 `ssh`s 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
    That would be then: [`if [[ $DISPLAY ]]; then … fi`](https://unix.stackexchange.com/a/398491/39845) – Serge Stroobandt Oct 16 '17 at 20:13
  • 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,429
  • 1
  • 20
  • 33
  • 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
  • 234,489
  • 66
  • 447
  • 667
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.

Serge Stroobandt
  • 2,314
  • 3
  • 32
  • 36
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,763
  • 7
  • 43
  • 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](http://user.it.uu.se/~embe8573/conf/.zshrc) `.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