Bagaimana cara mengidentifikasi terminal dari skrip?

8

Dan jangan katakan " $TERM" - itu selalu xterm.

Bagaimana bashskrip dapat mengetahui terminal apa yang sedang berjalan, khususnya apakah itu iTerm, Terminal.app, atau sebenarnya xterm?

Saya bertanya karena resettidak berfungsi di luar kotak pada Terminal.app dan iTerm2. Namun, iTerm2 mengenali urutan pelarian untuk melakukan reset terminal ( \x1b]50;ClearScrollback\x07), dan jika saya bisa mendeteksinya, saya bisa menimpanya resetdengan alias yang melakukan hal yang benar. AFAICT, Terminal.app tidak memiliki urutan reset, dan orang - orang menggunakan tom-hackery konyol untuk meretas itu .

Tujuan akhir saya di sini adalah untuk resetbekerja sama apakah saya bekerja pada OS X atau Linux, bekerja secara lokal atau jarak jauh melalui SSH. (Saya tidak ingin harus mencoba mengingat yang mana, dan ini berguna untuk melakukan reset && command-that-outputs-a-bunchdan memiliki pekerjaan yang masuk). Terminal.app dan iTerm melemparkan kunci pas dalam rencana ini dengan tidak menerapkan resetdengan benar.

Ini berarti bahwa mengganti saja resettidak cukup: jika saya menggunakan mesin Linux, itu perlu tahu apakah saya menggunakan gnome-terminalatau iTerm untuk mengirim urutan pelarian yang tepat.

Apakah ada cara (bahkan jika saya memerlukan ioctl) untuk bertanya terminal apa itu sebenarnya ?

¹Untuk keperluan pertanyaan ini, reset harus menghapus layar, mengatur ulang kursor, dan menghapus buffer scrollback.

Thanatos
sumber
Ya, ini adalah fitur, bukan bug, atau begitulah kata mereka. Apa yang terjadi jika Anda membuka Terminal.apppengaturan, tab terminal dan mengatur garis scrollback ke 0? Apakah itu menonaktifkan sebagian dan semua teks di atas baris saat ini, atau hanya apa pun di atas layar? Saya tahu, itu bukan apa yang Anda minta, layak dicoba.
nitro2k01
@ nitro2k01: Saya tidak yakin apa yang akan dicapai? Saya ingin scrollback. Saya hanya ingin bisa membersihkannya sekarang dan kemudian, lebih disukai dengan reset, karena itulah yang jari saya tahu.
Thanatos
Adapun masalah "reset" Anda: untuk memperjelas, Anda mengharapkan resetperintah untuk menghapus konten gulir-kembali emulator terminal, tetapi itu tidak dijamin untuk melakukan itu, karena gulir-kembali adalah fitur khusus terminal emulator, bukan benar-benar sebuah bagian dari terminal. Namun, Terminal mendukung ekstensi dari urutan pelepasan ED (Erase in Display) untuk menghapus scroll-back ESC [ 3 J. Anda dapat menghapus layar, lalu menggunakannya, misalnya,reset && printf '\e[3J’
Chris Page
Lihat jawaban saya di sini apple.stackexchange.com/a/113168/6883 untuk rincian lebih lanjut tentang ekstensi Erase dalam Tampilan.
Chris Page
@ ChrisPage: Saya menyadari bahwa terminal adalah hal yang aneh, tetapi jika Anda menyatakan diri Anda sebagai xterm(melalui TERM=xterm) saya berharap Anda meniru superset dari XTerm, yang menghapus scrollback-nya saat reset. (Sama seperti jika Anda mengirim urutan pelarian untuk "biru", Anda akan mengharapkan biru.) Memang, xterm saya mengatakan kepada saya bahwa Erase is backspace., yang saya syukuri tidak ada yang lain; itu hanya menjengkelkan.
Thanatos

Jawaban:

10

Gunakan $TERM_PROGRAM.

ITerm mengaturnya iTerm.app, dan Terminal.app ke Apple_Terminal.

Daniel Beck
sumber
Heh, oke, ini jelas lebih baik dari hack saya, +1 :). Retasan harus bekerja untuk emulator terminal apa pun, bukan hanya keduanya.
terdon
Tidak ada satu cara untuk mendeteksi setiap emulator terminal. Untuk xterm, Anda dapat memeriksa variabel $ XTERM_VERSION, misalnya. Itu akan membereskan apa yang mungkin merupakan tiga emulator paling populer di OS X.
Chris Page
Menerima ini, karena ini awal yang baik. Sayangnya, ini tidak semudah ini, karena variabel ini tidak tersedia di dalam sesi SSH. Saya menduga ada konfigurasi yang dapat saya edit untuk meneruskannya.
Thanatos
1
@Thanatos sshd_config's AcceptEnvmungkin. Karena ini (shell Anda berjalan pada host yang berbeda dari yang Terminal Anda jalankan) adalah informasi yang sangat penting, itu benar-benar harus menjadi bagian dari pertanyaan.
Daniel Beck
@DanielBeck: Ini tidak sepenuhnya terjadi; Saya ingin melakukan hal yang sama secara lokal dan jarak jauh. Yang ingin saya lakukan adalah mengetik "reset" ke terminal menyebabkan reset terminal, tidak peduli apakah saya menggunakan OS X atau Linux, bekerja secara lokal atau jarak jauh. Saya telah mengedit ini dalam pertanyaan.
Thanatos
1

$TERMtidak ada hubungannya sama sekali dengan emulator terminal yang sedang berjalan, itu hanya terminal default Anda dan dapat diatur untuk apa saja. Untuk mendapatkan nama emulator terminal yang Anda jalankan, Anda dapat menggunakan psuntuk mendapatkan PID dari proses induk shell Anda saat ini.

CATATAN: Hal berikut ini akan gagal pada OSX tetapi akan berfungsi OK di Linux

PID dari proses shell Anda saat ini adalah $$. Dari sana, Anda dapat menggunakan psuntuk menampilkan pohon proses, dan mencetak PID induk dari sesi shell Anda saat ini:

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

Anda kemudian dapat meneruskan PID itu ke psdan kirim untuk mencetak nama perintah:

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

Itu akan memotong nama, itu harus cukup bagi Anda untuk mengetahuinya tetapi mungkin tidak baik untuk skrip. Untuk mendapatkan nama lengkap, Anda bisa mencoba

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

Inilah yang saya dapatkan di sistem saya menggunakan beberapa terminal yang berbeda:

  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
sumber
Tidak berfungsi di OS X:ps: illegal option -- f
Daniel Beck
@DanielBeck darn gaya BSD, terima kasih. Bisakah Anda mencoba lagi dengan versi yang diperbarui? Menambahkan -sebelum opsi harus bekerja sesuai dengan OSX man ps.
terdon
Lebih baik, tetapi masih tidak berfungsi. Format output berbeda (PID adalah $2, PPID adalah $3), dan proses induk dari shell mungkin login(tergantung pada konfigurasi Terminal), dengan params yang berbeda. Namun, yang proses induk adalah Terminal. --no-headerstidak ada, Anda perlu sesuatu seperti tail -n1. Dan karena semua proses dengan UI memiliki argumen-psn_0_... , awk '{print $NF}'tidak berfungsi juga.
Daniel Beck
@DanielBeck yah sudah payah. OK, terima kasih saya akan menjelaskan bahwa ini gagal pada OSX.
terdon
Perhatikan bahwa ini hanya berfungsi secara lokal. Anda tidak dapat menggunakan pendekatan ini untuk mengetahui emulator terminal apa yang digunakan pada klien jarak jauh. Jawaban terbaik adalah mencari variabel seperti $ TERM_PROGRAM (sebagaimana disebutkan dalam jawaban @ DanielBeck) dan $ XTERM_VERSION untuk menyimpulkan aplikasi emulator.
Chris Page
0

Berikut cara portabel untuk mendapatkan nama atau jalur proses induk:

Hal 2:

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

gnome-terminal di Ubuntu:

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

Terminal.app:

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

Perhatikan bahwa jika Terminal.app diatur untuk membuka shell baru dengan shell login default, proses induk shell adalah logindan bukan terminal.

The commkolom path lengkap dari perintah di OS X dan nama perintah dipotong ke 15 karakter dalam pelaksanaan procps di Linux.

Lri
sumber
Mencoba di iTerm dan mendapat login- Apakah saya menyesuaikan profil saya beberapa waktu lalu untuk menjalankan perintah login -fp danielbeck?
Daniel Beck