Jak mogę uzyskać nazwę bieżącego terminala z wiersza poleceń?

25

Czy istnieje możliwość uzyskania typu terminala za pomocą polecenia?

Jeśli używam gnome-terminal, wyjście powinno być gnome-terminallub coś podobnego. Przydałaby się również wersja terminalu.

Aktualizacja

ps -aux | grep `ps -p $$ -o ppid=` 

wyświetli coś takiego:

user     4239  0.0  0.7 292708 15744 pts/8    Sl   11:39   0:02 xfce4-terminal
user     4800  0.0  0.0   6176   820 pts/0    S+   12:23   0:00 grep --color=auto  4239

Będzie to również działać z Xterm, ale jak uzyskać tylko nazwę ( xfce4-terminalw tym przypadku)?

TuKsn
źródło
Właśnie zaktualizowałem swoją odpowiedź, stosując inne i lepsze podejście. Jeśli masz czas, spójrz i daj mi znać, czy to również działa dla Ciebie.
terdon
Dzięki, ale pierwszy problem z rxvt -> window 31457282 has no pid associated with it(testowane na Lubuntu)
TuKsn
O? Cholera, to dziwne. Testowałem pod cynamonem.
terdon

Odpowiedzi:

29

Orginalna wersja

Jednym ze sposobów na to jest uzyskanie procesu nadrzędnego dla bieżącej sesji powłoki, a stamtąd nazwa terminala.

  1. Uzyskaj element nadrzędny bieżącego procesu powłoki. Zmienna bash $$jest PID twojej bieżącej powłoki, więc możemy podać to jako zapytanie do ps( -p $$) i poprosić go, aby wydrukował PID procesu nadrzędnego ( -o ppid=trailing =ma na celu uniknięcie drukowania nagłówków kolumn):

    $ ps -p $$ -o ppid=
    544
    

    Tak więc PID rodzica mojej powłoki to 544.

  2. Pobierz proces powiązany z tym PID i wydrukuj jego wiersz poleceń

    $ ps -p 544 o args=
    /usr/bin/python /usr/bin/terminator
    

    Powyższe dane wyjściowe będą zależeć od używanego emulatora terminala, którego używam terminator.

  3. Połącz wszystko w jednym poleceniu

    ps -p $(ps -p $$ -o ppid=) o args=
    
  4. Użyj tego, aby uzyskać wersję

    $(ps -p $(ps -p $$ -o ppid=) o args=) --version
    terminator 0.97
    
  5. Dodaj do swojej funkcji małą funkcję, ~/.bashrcktóra zwraca nazwę i wersję używanego emulatora terminala (działa to w przypadku większości popularnych emulatorów terminali):

    which_term(){
        term=$(ps -p $(ps -p $$ -o ppid=) -o args=);
        found=0;
        case $term in
            *gnome-terminal*)
                found=1
                echo "gnome-terminal " $(dpkg -l gnome-terminal | awk '/^ii/{print $3}')
                ;;
            *lxterminal*)
                found=1
                echo "lxterminal " $(dpkg -l lxterminal | awk '/^ii/{print $3}')
                ;;
            rxvt*)
                found=1
                echo "rxvt " $(dpkg -l rxvt | awk '/^ii/{print $3}')
                ;;
            ## Try and guess for any others
            *)
                for v in '-version' '--version' '-V' '-v'
                do
                    $term "$v" &>/dev/null && eval $term $v && found=1 && break
                done
                ;;
        esac
        ## If none of the version arguments worked, try and get the 
        ## package version
        [ $found -eq 0 ] && echo "$term " $(dpkg -l $term | awk '/^ii/{print $3}')    
    }

    Możesz teraz uzyskać nazwę terminala, a także przekazać dowolną opcję, którą lubisz (np --version.

Niektóre przykłady z wykorzystaniem różnych terminali:

  1. xterm

    $ which_term
    XTerm(297)
    
  2. terminator

    $ which_term 
    terminator 0.97
    
  3. rxvtTen jeden ma żaden z -V, -versionlub --versionflagi więc nie ma informacji wersja zostanie wydrukowany.

    $  which_term
    rxvt  1:2.7.10-5
    
  4. gnome-terminal.

    $ which_term
    gnome-terminal  3.10.1-1
    
  5. konsole

    $ which_term
    Qt: 4.8.6
    KDE Development Platform: 4.11.3
    Konsole: 2.11.3
    
  6. lxterminal

    $ which_term
    lxterminal  0.1.11-4
    
  7. xfce4-terminal

    $ which_term
    xfce4-terminal 0.6.2 (Xfce 4.10)
    
    Copyright (c) 2003-2012
        The Xfce development team. All rights reserved.
    
    Written by Benedikt Meurer <[email protected]>
    and Nick Schermer <[email protected]>.
    
    Please report bugs to <http://bugzilla.xfce.org/>.
    

Nowe i ulepszone

Powyższe podejście nie jest jednak tak godne zaufania. Dusi się, gdy uruchomisz powłokę po suwysłaniu wiadomości do innego użytkownika lub gdy twój terminal jest aliasowany do czegoś i różnych innych przypadków. Ponieważ oczywiście pracujemy tutaj z programami X, lepszym sposobem może być użycie czegoś takiego xdotool(instalowanego z sudo apt-get install xdotool), aby uzyskać informacje:

perl -lpe 's/\0/ /g' /proc/$(xdotool getwindowpid $(xdotool getactivewindow))/cmdline

Powyżej wydrukuje wiersz poleceń użyty do uruchomienia aktualnie aktywnego okna. Ponieważ twój terminal prawdopodobnie będzie aktywny, to polecenie, które pokaże. Oznacza to, że w przypadku większości emulatorów terminali można bezpiecznie założyć, że zwrócone 1. pole to nazwa terminala:

$ which_term 
lxterminal 

Oznacza to, że uzyskanie wersji jest banalne. Na przykład

$ dpkg -l $(which_term) | awk '/^ii/{print $3}'
0.1.11-4

Nie dotyczy to gnome-terminal:

$ which_term 
/usr/lib/gnome-terminal/gnome-terminal-server 

lub terminator:

$ which_term
/usr/bin/python /usr/bin/terminator 

Możemy więc uczynić to nieco bardziej złożonym (tutaj są pewne bashizmy, ten nie jest przenośny):

which_term(){
    term=$(perl -lpe 's/\0/ /g' \
           /proc/$(xdotool getwindowpid $(xdotool getactivewindow))/cmdline)

    ## Enable extended globbing patterns
    shopt -s extglob
    case $term in
        ## If this terminal is a python or perl program,
        ## then the emulator's name is likely the second 
        ## part of it
        */python*|*/perl*    )
         term=$(basename "$(readlink -f $(echo "$term" | cut -d ' ' -f 2))")
         version=$(dpkg -l "$term" | awk '/^ii/{print $3}')
         ;;
        ## The special case of gnome-terminal
        *gnome-terminal-server* )
          term="gnome-terminal"
        ;;
        ## For other cases, just take the 1st
        ## field of $term
        * )
          term=${term/% */}
        ;;
     esac
     version=$(dpkg -l "$term" | awk '/^ii/{print $3}')
     echo "$term  $version"
}

Działa to we wszystkich przypadkach, w których testowałem.

terdon
źródło
@ Xubu-Tur hmm, próbowałem tylko uruchamiając każdy terminal z innego terminala ręcznie i działało dobrze. Domyślam się, że menu środowiska pulpitu mają inną ścieżkę lub w jakiś sposób różnią się sposobem uruchamiania terminali. Mogę dać ci coś lepszego, jeśli powiesz mi dokładnie, jak je uruchomiłeś i jaki masz błąd. Jeśli uruchomiłeś z menu, sprawdź, jakie polecenie uruchamia element menu.
terdon
@ Xubu-Tur nie dodawaj zrzutu ekranu. Po prostu wklej komunikat o błędzie do swojego pytania. To samo dla każdego polecenia, które uruchamia element menu. Nie oczekuj, że ręcznie skopiuję go ze zdjęcia!
terdon
2
Możesz po prostu użyć, $PPIDaby uzyskać PID procesu nadrzędnego.
nyuszika7h
@ nyuszika7h tak, możesz i +1 za to, ale wolałbym nie. Właśnie sprawdziłem i nie jest dostępny w kshlub tcsh. Jest to jednak bardzo dobry pomysł dla rodziny bash, ponieważ jest to znacznie prostsze niż moje podejście.
terdon
Jest zdecydowanie dostępny w ksh93i mksh.
nyuszika7h
8

Spróbuj tego,

ps -aux | grep `ps -p $$ -o ppid=` | awk 'NR==1{print $11}'

LUB

ps -aux | grep `ps -p $$ -o ppid=` | awk 'NR==1{print $NF}'
Avinash Raj
źródło
Pierwszy zawiedzie, rxvta terminatordrugi zawiedzie uxtermi gnome-terminal(drukuje /usr/lib/gnome-terminal/gnome-terminal-server). Wszystkie zawiodą (podobnie jak moje), jeśli używasz sesji su.
terdon
7
basename "$(cat "/proc/$PPID/comm")"

$PPIDjest PID procesu macierzystego powłoki. commoznacza polecenie . Może to być pełna ścieżka, ale basenamew razie potrzeby używamy jej do usuwania.

Ostrzeżenia

Prawdopodobnie dotyczą one przynajmniej niektórych innych odpowiedzi.

  • commjest technicznie argv[0], co w rzeczywistości może być dowolnym ciągiem. Ale ogólnie powinieneś być w stanie polegać na tym w tym konkretnym przypadku.

  • To nie będzie działać, jeśli połączyć się przez SSH lub wykorzystania zgodnie z oczekiwaniami tmux, screenlub coś podobnego.

nyuszika7h
źródło
To jest bardzo fajne +1, ale na terminalu terminatora dostaję tylko terminjako wynik.
TuKsn
Nie wiem dlaczego, to pewnie wina Terminatora.
nyuszika7h
To dlatego, że myślę, że jest uruchamiany jako skrypt Pythona. To jest naprawdę denerwujące.
terdon
Pamiętaj, że $PPIDnie jest to standard we wszystkich powłokach. np. tcshdostaję:PPID: Undefined variable.
arielf
2

Możesz spróbować wykonać następujące polecenie:

$ dpkg-query -W $COLORTERM
gnome-terminal  3.6.2-0ubuntu1

Aktualizacja (dzięki OP i Avinash Raj):

$ dpkg-query -W $(ps -aux | grep "`ps -p $$ -o ppid=`" | awk 'NR==1{print $11}' | xargs basename)
rxvt    1:2.7.10-5
Sylvain Pineau
źródło
Myślę, że chce to wiedzieć podczas aktywnej sesji terminalu :) Więc jeśli używa w tym czasie „szpachli” ...
Rinzwind
Nie, nie „putty”, ale co z Xterm, dzięki temu poleceniu dostaję się także gnome-terminal 3.6.2-0ubuntu1ldo Xterm?
TuKsn
2
Nie drukuje to terminalu, którego obecnie używasz. Drukuje wszystko, co zostało ustawione jako domyślny $ COLORTERM, który nie ma nic wspólnego z tym, czego używasz w tym czasie.
terdon
Aktualizacja działa dobrze również z Xterm i pokazuje wersję i nazwę.
TuKsn
Cały kredyt należy do @Avinash, a ty za właściwe polecenie. Właśnie dodałem wersję.
Sylvain Pineau
2

Inną (nie idealną) możliwością jest:

xprop -id $WINDOWID WM_CLASS | cut -d" " -f3 | sed 's/^.\(.*\)..$/\1/'

Ale to nie działa z lxterminal, ponieważ zmienna środowiskowa jest $WINDOWIDpusta ...

Terminator pokazuje nazwę „x-terminal-emulator”.

TuKsn
źródło
0

Bieżący terminal można również wykryć za pomocą sekwencji ucieczki: Atrybuty urządzenia (drugorzędne DA)

Na przykład w bash:

read -s -dc -p $'\E[>c' da;da=${da##$'\E'[>};echo "${da//;/ }"

Zwraca tylko jakiś identyfikator - i niestety nie znam oficjalnej listy, która tłumaczy je na rzeczywiste nazwy.


Aby zobaczyć prawdziwą implementację, która tłumaczy niektóre znane identyfikatory na nazwy terminali, zobacz ten przykładowy skrypt bash: https://github.com/mintty/utils/blob/master/terminal

TS
źródło