5
\$\begingroup\$

I wanted to bind a single hot key to open and close gnome-terminal in a way similar to terminal emulators such as tilda or guake. I use Ubuntu, and have configured this script to be executed when I press the key F1

The script will focus or minimize the first gnome-terminal window that is running. If no gnome-terminal is running, it will start a new one and place it in the top half of the screen.

#!/bin/bash
# Bind this script to a keyboard shortcut to add "pull-down" behaviour to
# the Gnome terminal similar to guake or tilda

# It seems to work with gnome-terminal or xfce4-terminal
# I haven't tested any other terminal emulators
TERMINAL_EMULATOR=gnome-terminal

function main {
  if [[ -z $(terminal_process) ]]; then
    # no running terminal emulator
    # open new terminal at top of the screen
    $TERMINAL_EMULATOR --geometry 80x1+0+0 &
    win_id=$(get_terminal_window)
    # set initial width to 100% and height to 45%
    xdotool windowsize $win_id $(absolute_window_size 100 45)
    xdotool windowactivate $win_id
  else 
    win_id=$(get_terminal_window)
    if [[ $(xdotool getactivewindow) == $win_id ]]; then
      # if terminal window is active, mimize
      xdotool getactivewindow windowminimize
    else
      # if terminal window is inactive, bring in focus
      xdotool windowactivate $win_id
    fi
  fi
}

function terminal_process {
  # Is gnome-terminal already running
  echo $( ps aux | grep $TERMINAL_EMULATOR | grep -v grep)
}

function get_terminal_window {
  # get id of open terminal window. Will wait for window to open if neccessary
  echo $(xdotool search --onlyvisible --sync --limit 1 --class $TERMINAL_EMULATOR)
}

function absolute_window_size {
  # convert relative window size to absolute pixel size, based on screen res
  width_percent=$1
  height_percent=$2
  IFS=x
  screen_dimensions=$(xrandr | grep connected | grep -o '[1-9]\+x[0-9]\+')
  set $screen_dimensions
  echo $(($width_percent*$1/100)) $(($height_percent*$2/100))
}

main

As someone coming from python, bash feels quite unfamiliar, and I would like some feedback on whether this script follows best practices. I also wonder if there's anything that can be simplified without losing readability.

\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

Instead of this:

function terminal_process {
  # Is gnome-terminal already running
  echo $( ps aux | grep $TERMINAL_EMULATOR | grep -v grep)
}

You don't need the echo, you can let the standard output simply go through:

terminal_process() {
  # Is gnome-terminal already running
  ps aux | grep $TERMINAL_EMULATOR | grep -v grep
}

The same goes for get_terminal_window too.

Notice that I also changed the wording style of the function definition. This is the recommended style in bash, I suggest to apply this to all your functions.


You can actually go even further. [[ -z $(terminal_process) ]] is actually a text comparison, checking if the output of the command as a string is empty. Instead of that, it would be better to use the exit code of the function, like this:

if ! terminal_process; then
    # ...

This works, because the exit of grep will be success (= 0) if it matched something (process exists), and failure (non-zero) if it didn't match.

However, when using the function like this, since the output of grep is not captured within a $(...), it will be printed on stdout, which you probably want to avoid. You can easily suppress that by adding the -q flag:

terminal_process() {
  # Is gnome-terminal already running
  ps aux | grep $TERMINAL_EMULATOR | grep -qv grep
}

This can also be simplified:

echo $(($width_percent*$1/100)) $(($height_percent*$2/100))

Like this:

echo $((width_percent * $1 / 100)) $((height_percent * $2 / 100))
\$\endgroup\$
2
  • \$\begingroup\$ Will $(function_call), catch everything that goes to stdout in the function? \$\endgroup\$
    – Håken Lid
    Feb 5, 2016 at 8:12
  • 1
    \$\begingroup\$ Yes it will. But actually I added an even better solution that doesn't need stdout at all, see my updated answer. \$\endgroup\$
    – janos
    Feb 5, 2016 at 8:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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