9

I have a Bash script I was trying to make to help me run a rather complex command with small changes that it would ask me about through echo and read.

I have found solutions to force it to run a terminal to execute the command, but I'm not interested in that. What I would like it to do is, if I space out and just hit Enter on it in Nautilus (making it run with Run Software), it'll just gently pop up a notification saying "Please run this from a terminal."

I can get the popup to happen -- as in I know the command -- but I can't get the Bash script to tell if it's being run inside a terminal or not, it seems to always think so. Is it even possible?

9

From man bash under CONDITIONAL EXPRESSIONS:

-t fd  
    True if file descriptor fd is open and refers to a terminal.

Assuming fd 1 is standard out, if [ -t 1 ]; then should work for you. The Advanced Shell Scripting Guide claims that -t used this way will fail over ssh, and that the test (using stdin, not stdout) should therefore be:

if [[ -t 0 || -p /dev/stdin ]]

-p tests if a file exists and is a named pipe. However, I'd note experientially this is not true for me: -p /dev/stdin fails for both normal terminals and ssh sessions whereas if [ -t 0 ] (or -t 1) works in both cases (see also Gilles comments below about issues in that section of the Advanced Shell Scripting Guide).


If the primary issue is a specialized context from which you wish to call the script to behave in a way appropriate to that context, you can sidestep all these technicalities and save your self some fuss by using a wrapper and a custom variable:

!#/bin/bash

export SPECIAL_CONTEXT=1
/path/to/real/script.sh

Call this live_script.sh or whatever and double click that instead. You could of course accomplish the same thing with command line arguments, but a wrapper would still be needed to make point and click in a GUI file browser work.

  • 5
    this is the correct answer - it is also how POSIX says a shell should detect if it is interactive or not. – mikeserv Oct 18 '14 at 15:26
  • 2
    @DanielAmaya - if you redirect input then the script is not being run on a terminal. The question is how to detect if the script is being run on a terminal. – mikeserv Oct 18 '14 at 16:02
  • 2
    Are you sure about the use of || within [ … ] like that? If you use [[ … ]] then it would be fine, but normally the || is used to separate commands, and [ -t 0 is an incorrect invocation of [ because its last ] is missing. There typically isn't a command -p either. I agree with testing for a terminal; that's probably the way to do it. It's just the syntax I'm concerned about. – Jonathan Leffler Oct 18 '14 at 16:14
  • 1
    @JonathanLeffler Right; that should produce a syntax error, since the shell operator || is seen before the required final ] argument to [. – chepner Oct 18 '14 at 17:44
  • 3
    That section from the Advanced Bash-Scripting Guide has several errors. PS1 is not a reliable test to tell whether the shell is interactive. “If a script needs to test whether it is running in an interactive shell” is also confusing: it should be if some code needs to test — a script is usually not running in an interactive shell (but it can be, if it's sourced). Testing for i in $- is the correct way to test if the shell is interactive. Testing -t 0 or -t 2 is the correct way to tell if the script is running in a terminal, which is different from being interactive. – Gilles Oct 18 '14 at 20:37
0

Use the bash $SHLVL variable to detect the level of shell nesting. In a script run 'raw' by double-clicking it will be 1, in a script running within a terminal it will be 2.

#!/bin/bash
if (( SHLVL < 2 )) ; then
    echo "Please run this from a terminal."
    read -p "Press <Enter> to close this window"
    exit 1
fi
# rest of script
-2

Another, using the bash options set internal variable, $-.

From .bashrc,

# If not running interactively, don't do anything
case $- in
    *i*) ;;
    *) return;;
esac
  • an interactive shell isnt necessarily connected to a terminal. while one started with that connection is automatically started interactive, this also is possible: cmd | sh -i | cmd. – mikeserv Oct 18 '14 at 15:30
  • This code is being executed in a script. It won't be interactive, even if it is running in a terminal. – Gilles Oct 18 '14 at 20:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.