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


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
    

Не работает на 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.


Попробовал в iTerm и получил login- настроил ли я свой профиль некоторое время назад для запуска команды login -fp danielbeck?
— Даниэль Бек
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.