26

I have gnome-terminal and Guake installed. I want to give different startup messages to be displayed on these terminal emulators as they start. What code should I write in .bashrc so that this is achieved?

1
  • Although both the accepted and top voted answers are good enough for what was asked, I strongly suggest everybody to take a look at this answer instead. It is simpler and much more portable than the others. Apr 28, 2023 at 13:59

11 Answers 11

18

You can get the terminal emulator name, by grepping the parents process name. Therefore it works with every terminal emulator.

In bash, zsh, etc.:

basename "/"$(ps -o cmd -f -p $(cat /proc/$(echo $$)/stat | cut -d \  -f 4) | tail -1 | sed 's/ .*$//')

With fish-shell:

basename "/"(ps -o cmd -f -p (cat /proc/(echo %self)/stat | cut -d \  -f 4) | tail -1 | sed 's/ .*$//')
4
  • Do note however, that this will catch program arguments when the terminal emulator is launched with them. Jun 16, 2017 at 13:53
  • Does this work if I'm connected using SSH? Mar 21, 2018 at 17:38
  • @user3731622 it won't! You'll have to forward it from the client.
    – Enrico
    Jul 6, 2018 at 3:51
  • 2
    Finally; an answer that works :-) Sep 10, 2020 at 1:13
16

Try this:

echo $TERM

This is more authoritative, but could be messed up by your programs. However on mine, it says xterm and on ttys it says linux, which I think stands for Linux Console.

1
  • 5
    $TERM is a variable which refers to the specification as self-reported by the terminal emulator you are using, not to the actual emulator itself. For example, on my system, echo $TERM returns xterm even though I am actually running lxterminal. What is happening is lxterminal self-reports xterm compliance. lxterminal is not actually fully xterm compliant, so you have to watch out. The spec files are usually located in /usr/share/terminfo.
    – stazher
    Dec 31, 2016 at 22:44
13

This function should do the job:

container() {
    pid=$$
    while true; do
        pid=$(ps -h -o ppid -p $pid 2>/dev/null)
        case $(ps -h -o comm -p $pid 2>/dev/null) in
        (gnome-terminal) echo "Running in gnome terminal";return;;
        (xterm) echo "Running in xterm";return;;
        (rxvt) echo "Running in rxvt";return;;
        (python) if [ ! -z "$(ps -h -o args -p $pid 2>/dev/null | grep guake)" ]; then echo "Running in Guake"; return; fi ;;
        esac
        [[ $(echo $pid) == 1 ]] && break
    done
}
container
1
  • 1
    Nice answer! Don't forget to actually call the function with container after the definition.
    – rosch
    Oct 31, 2012 at 18:43
5

On many linux system echo $TERM return xterm see stazher post above.

To get actual terminal in use, do this:

1: Close every terminal instance currently running.

2: Open new terminal using your usual method.

3: Enter command as follows:

ps -o 'cmd=' -p $(ps -o 'ppid=' -p $$)

4: Return should be something like such:

lxterminal --geometry=135x20

Here is breakdown:

So: ps is "process status"

ps option -o is Display information associated with the space or comma separated list of keywords specified. Sounds complicated, but is not really. (space or comma) separated (list of keywords) specified.

So, (list of keywords) is 'cmd=' Only one keyword in list. So, just asking to display command to open terminal.

ps option -p is "by process id" Wow this is very nice option for ps. Problem is, you must pass to ps this process id. So, how to get process id? We unwrap expression $(ps -o 'ppid=' -p $$)

Here we must start to think a little deeper. I wish I invented this bash one-liner, but I did not. I think I stole it from https://wiki.archlinux.org/ somewhere, I could not find again. Those guys are awesome, but many times I cannot understand what they say to do until after much study. What we can do, is to understand it now, because I will explain.

so we know $ is expansion operator in bash. I like to think "un-wrap". So, $(foo -opt bar) will unwrap, or expand, "foo -opt bar". But in bash, single round brace (...) opens subshell.

So, $(foo -opt bar) expands "foo -opt bar" as run in daughter shell. Very weird and difficult to understand.

OK, so now we are running almost identical command again, ps -o 'ppid=' -p $$ but this time ps, process status, shows us what he can see from within daughter shell instance.

-o list of keywords, only one keyword as before, but ppid= this is asking directly for process id of parent shell!! From WITHIN DAUGHTER SHELL! Very clever, yes? I am so excited when I can understand this!

-p again, "by process id" and in bash $$ is the process id.

If you call ps -o 'ppid=' -p $$ , or any other command asking for $$ directly from the first shell, he might say pid=1, or the pid from xWindow, or from your desktop program, or you maybe get actual pid of shell. If you ask many times, you maybe get different answer each time!

But, if you invoke a daughter and ask her "Who's your Daddy" she will tell you! Very clever. I wish I could be such genius to invent this method.

6
  • OK so AU will not allow proper breakdown within one post. Sorry, not willing to fight with blog system and make multiple posts. Maybe you can get idea.
    – stazher
    Dec 31, 2016 at 23:45
  • Your other answer seems to be a sophisticated and informative comment on this answer rather than an answer to the question... It would be great if you could combine your two answers into one and delete one of them, and add to it so that it fully answers the question. Use ---- to draw a line in the middle? There is a button also.
    – Zanna
    Jan 1, 2017 at 1:01
  • I think I have answered OP question exactly, and in detail.You jumped on me before I had a chance understand blog edit system and to finish. Bring on the down votes, I am used to it.
    – stazher
    Jan 1, 2017 at 7:43
  • 1
    I don't think I jumped on you, I was just doing review... thanks for making your post more complete
    – Zanna
    Jan 1, 2017 at 7:57
  • Thank you for your response. I am sorry, maybe I jumped on you. I apologise very much.
    – stazher
    Jan 1, 2017 at 8:02
3

Using pstree and awk is the easyest way:

pstree -sA $$ | awk -F "---" '{ print $2 }'

Explaining

  1. Display a tree of processes with pstree of $$ (the atual process).
  2. The pstree arguments:

    • -s: display the parents of a process
    • -A: display output in pure ASCII.
  3. The awk tool scan a pattern and -F argument is used to split the processes.

  4. Finally '{ print $2 }'tells to awk to output only the 2nd match pattern (in this case, the terminal emulator name).
4
  • Are you sure about $2? In my case, what is piped in into awk is actually systemd---lightdm---lightdm---upstart---gnome-terminal----bash---pstree...
    – Enlico
    Jun 19, 2018 at 9:44
  • @EnricoMariaDeAngelis Ya. Thank you for your observation. In my case the terminal emulator initializes directly in systemd service. I check again the code and edit it with a correction.
    – silvadev
    Jun 20, 2018 at 11:35
  • This doesn't work when I use a keyboard shortcut to launch the emulator. On XFCE, I get xfsettingsd instead of the terminal I'm using. Sep 22, 2018 at 5:26
  • 2
    Works better if you start from the end: pstree -sA $$ | head -n1 | awk -F "---" '{ print $(NF-1) }'
    – lleaff
    Dec 20, 2018 at 23:33
3

Use

readlink "/proc/$(cat /proc/$(echo $$)/stat|cut -d ' ' -f 4)/exe"
  • $$ is the current shell process id (bash, zsh, sh, etc)
  • /proc/[pid]/stat is status information about the current shell process
  • cut -d ' ' -f 4 will get the first 4th text split by space
  • /proc/[pid]/exe is a symlink to the executable
  • readlink will get the destination of a symlink
1
  • Thanks! This answer seems to be much more portable than both the accepted and the top voted answers. This one will work with Busybox's ps, which lacks many command line options the accepted answer requires. Apr 28, 2023 at 13:55
2

So many complicated answer, maybe I am missing something, but this simple command does the job for me in bash:

ps -p $PPID -o comm=
0

You are correct, I only made answer for headline question, not question in body. So here you go, and Bob's yer Uncle.

I am not sure what the case switch was about, in one answer shown above. Such case switch is not needed. My ~/.bashrc script is actually only one simple line, all the echo commands are just for fun. How to explain...

Any term when starting reads ~/.bashrc , and executes whatever commands he will see in .bashrc. So, no matter which term is called, he will read .bashrc and execute the commands, so only structure needed in .bashrc would be to modify the behavior of or exclude one term or another. Desired behavior is for every term to execute same command, so case switch not needed. Terminal himself will tell you how he was called, so there is no need to differentiate.

Note (1) I did not test for guake, but works for all others mentioned in first answer by jlliagre.

Note (2) Due to formatting in markdown for wiki, you can not cut and paste as shown. You must delete each backtick, including to delete the underline characters, and add actual backtick, with no space before the ps or after the -p $$).

script for ~/.bashrc

# show welcome message for actual terminal in use
echo "Welcome.  You are attempting to use"
echo ""
echo _backtick_ps -o 'cmd=' -p $(ps -o 'ppid=' -p $$)_backtick_
echo ""
echo "Good Luck and God Speed."

This was much fun. I have added this to my own ~/.bashrc.

1
  • per Note(1), have tested on Tilda, works fine. Guake is similar to Tilda, but is written in python, so still do not know about Guake.
    – stazher
    Jan 1, 2017 at 20:38
0

if you are using bash , I thing this command will help you :

which $(ps -o 'cmd=' -p $(ps -o 'ppid=' -p $$))

1
  • 1
    without the which $( ) still returns the path to it
    – mekb
    Sep 1, 2021 at 0:54
0

If you were using ZSH, there is a better (faster) solution, which only uses ZSH builtins and manipulates /proc/$pid/{stat,cmdline} directly.

get-terminal-emulator() {
    if [[ $TTY = "/dev/tty"* ]]; then
        echo "linux-console"
        return
    fi
    local pid=$$ name=''
    while true; do
        proc_stat=(${(@f)$(</proc/${pid}/stat)})
        name=${proc_stat[2]//[()]/}
        case "${name}" in
            gnome-terminal|konsole|rxvt|xterm)
                echo "${name}"; return ;;
            python*)
                local cmdline=(${(@f)$(</proc/${pid}/cmdline)})
                if [[ "$cmdline" =~ "\\bguake.main\\b" ]]; then
                    echo "guake"; return
                fi
                ;;
        esac
        if test "$pid" = "1" -o "$pid" = ""; then
            echo "unknown"
            return
        fi
        pid=${proc_stat[4]}       
    done
}
0

This solution find the parent process of the running shell and than look for the parent process that is the terminal emulator:

pid=`ps -axo "pid,ppid,command" | grep $$ | head -n 1| awk '{print $2}'`; ps -axo "pid,ppid,command" | grep $pid | head -n 1 | awk '{$1=""; $2=""; print}'
1
  • might not work if there is a process name of that process id
    – mekb
    Aug 31, 2021 at 8:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .