Как идентифицировать терминал из скрипта?

8

И не говори " $TERM" - это всегда xterm.

Как bashскрипт может сказать, в каком терминале он работает, в частности, это iTerm, Terminal.app или на самом деле xterm?

Я спрашиваю, потому resetчто не работает из коробки на Terminal.app и iTerm2. iTerm2, однако, распознает escape-последовательность для выполнения перезагрузки терминала ( \x1b]50;ClearScrollback\x07), и если бы я мог ее обнаружить, я мог бы переопределить resetпсевдоним, который делает правильные вещи. На самом деле, Terminal.app не хватает последовательности сброса, и люди прибегают к нелепым хакерским действиям, чтобы взломать это .

Моя конечная цель здесь - resetработать одинаково, работаю ли я на OS X или Linux, работаю локально или удаленно через SSH. (Я не хочу пытаться вспомнить, какие именно, и это полезно делать reset && command-that-outputs-a-bunchи начинать работу.) Terminal.app и iTerm вносят рывок в этот план из-за resetнеправильной реализации .

Это означает, что просто переопределение resetне совсем так: если я на машине с Linux, он должен знать, использую ли я gnome-terminalили iTerm, чтобы отправить правильную escape-последовательность.

Есть ли способ (даже если мне нужно ioctl) спросить терминал, что это на самом деле ?

¹ Для целей этого вопроса сброс должен очистить экран, сбросить курсор и стереть буфер прокрутки.

Танатос
источник
Ну, это особенность, а не ошибка, или так говорят. Что произойдет, если вы откроете Terminal.appнастройки, вкладку терминала и установите для строк прокрутки значение 0? Отключает ли это какой-либо текст над текущей строкой или что-нибудь над верхней частью экрана? Я знаю, это не совсем то, что вы просили, стоит попробовать.
nitro2k01
@ nitro2k01: Я не уверен, что это сделает? Я хочу прокрутку. Я просто хочу быть в состоянии очистить это время от времени, предпочтительно с reset, так как это то, что знают мои пальцы.
Танатос
Что касается вашей проблемы «сброса»: чтобы уточнить, вы ожидаете, что resetкоманда очистит содержимое прокрутки в эмуляторе терминала, но это не гарантировано, потому что прокрутка назад является специфичной для эмулятора терминала функцией, а не часть терминала. Тем не менее, терминал поддерживает расширение escape-последовательности ED (Erase in Display) для удаления прокрутки назад ESC [ 3 J. Вы можете очистить экран, а затем использовать это, например,reset && printf '\e[3J’
Крис Page
Смотрите мой ответ здесь apple.stackexchange.com/a/113168/6883 для более подробной информации о расширении Erase in Display.
Крис Пейдж
@ChrisPage: Я понимаю, что терминалы - это странные вещи, но если вы объявите себя xterm(сквозным TERM=xterm), я бы ожидал, что вы эмулируете расширенный набор XTerm, который очищает его прокрутку при перезагрузке. (Точно так же, как если бы вы послали escape-последовательность для «blue», вы бы ожидали синего цвета.) Конечно, мой xterm говорит мне об этом Erase is backspace., что, я благодарен, больше ничего не делает; это просто раздражает.
Танатос

Ответы:

10

Использование $TERM_PROGRAM.

iTerm устанавливает его iTerm.app, а Terminal.app - Apple_Terminal.

Даниэль Бек
источник
Хех, окей, это явно лучше моего хака +1 +1. Хак должен работать на любом терминальном эмуляторе, а не только на этих двух.
Тердон
Не существует единого способа обнаружить каждый эмулятор терминала. Например, для xterm вы можете проверить переменную $ XTERM_VERSION. Это позаботится о том, какие, вероятно, три самых популярных эмулятора в OS X.
Крис Page
Принимая это, так как это хорошее начало. К сожалению, это не так просто, так как эта переменная недоступна в сеансе SSH. Я подозреваю, что есть конфиги, которые я могу отредактировать для пересылки.
Танатос
1
@Tanatos sshd_config, AcceptEnvвероятно. Так как это (ваша оболочка работает на другом хосте, чем тот, на котором работает ваш терминал) очень важная информация, она действительно должна быть частью вопроса.
Даниэль Бек
@DanielBeck: Это не совсем так; Я хотел бы сделать то же самое локально и удаленно. Я хочу сказать, что ввод «reset» в терминале вызывает сброс терминала, независимо от того, работаю я в OS X или Linux, работаю локально или удаленно. Я отредактировал это в вопросе.
Танатос
1

$TERMне имеет никакого отношения к эмулятору терминала, работающему в данный момент, это просто ваш терминал по умолчанию и может быть установлен на что угодно. Чтобы получить имя эмулятора терминала, который вы используете, вы можете использовать psдля получения PID родительского процесса вашей текущей оболочки.

ПРИМЕЧАНИЕ: следующее не будет работать в OSX, но должно работать нормально в Linux

PID вашего текущего процесса оболочки является $$. Оттуда вы можете использовать, psчтобы показать дерево процессов и распечатать PID родителя вашего текущего сеанса оболочки:

ps -axjf | awk -v pid=$$ '($2==pid){print $1}'

Затем вы можете передать этот PID psи сказать ему напечатать имя команды:

ps -o comm=  $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}')

Это будет усекать имя, вам должно хватить, чтобы понять его, но это может быть плохо для сценариев. Чтобы получить полное имя, вы можете попробовать

ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}'

Вот что я получаю в своей системе, используя несколько разных терминалов:

  1. terminator

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/bin/x-terminal-emulator
    
  2. gnome-terminal

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/lib/gnome-terminal/gnome-terminal-server
    
  3. xterm

    $ ps --no-headers $(ps axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    xterm
    
terdon
источник
Не работает на OS X:ps: illegal option -- f
Даниэль Бек
@DanielBeck чертовски стиль BSD, спасибо. Не могли бы вы попробовать еще раз с обновленной версией? Добавление параметров -перед должно работать в соответствии с OSX man ps.
Тердон
Лучше, но все еще не работает. Формат вывода отличается (PID есть $2, PPID есть $3), а родительский процесс оболочки может быть login(в зависимости от конфигурации терминала) с разными параметрами. Тем не менее, его родительский процесс Terminal. --no-headersне существует, вам нужно что-то вроде tail -n1. И поскольку все процессы с пользовательским интерфейсом имеют аргумент-psn_0_... , awk '{print $NF}'тоже не работает.
Даниэль Бек
@DanielBeck хорошо, значит, хренов. Хорошо, спасибо, я поясню, что это не работает на OSX.
Тердон
Обратите внимание, что это работает только локально. Вы не можете использовать этот подход, чтобы выяснить, какой эмулятор терминала используется на удаленном клиенте. Лучший ответ - искать переменные, такие как $ TERM_PROGRAM (как упомянуто в ответе @ DanielBeck) и $ XTERM_VERSION, чтобы вывести приложение эмулятора.
Крис Пейдж
0

Вот портативный способ получить имя или путь родительского процесса:

iTerm 2:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
/Applications/iTerm.app/Contents/MacOS/iTerm

гном-терминал в Ubuntu:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
gnome-terminal

Terminal.app:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
login

Обратите внимание, что если Terminal.app настроен на открытие новых оболочек с помощью оболочки входа по умолчанию, родительский процесс оболочки - это loginне терминал.

commКолонна является полным путем команды в OS X и имя команды усечен до 15 символов в реализации PROCPS в Linux.

LRI
источник
Попробовал в iTerm и получил login- настроил ли я свой профиль некоторое время назад для запуска команды login -fp danielbeck?
Даниэль Бек