Bagaimana mengelabui perintah dengan berpikir outputnya akan ke terminal

38

Diberikan perintah yang mengubah perilakunya ketika outputnya menuju ke terminal (mis. Menghasilkan keluaran berwarna), bagaimana output itu dapat dialihkan dalam pipa sambil mempertahankan perilaku yang berubah? Pasti ada utilitas untuk itu, yang tidak saya sadari.

Beberapa perintah, seperti grep --color=always, memiliki flag opsi untuk memaksa perilaku, tetapi pertanyaannya adalah bagaimana menangani program yang hanya mengandalkan pengujian deskriptor file output mereka.

Jika itu penting, shell saya ada bashdi Linux.

Amir
sumber
Anda harus tahu bagaimana perintah menguji descriptor file outputnya dan entah bagaimana mengembalikan hasil yang konsisten dengan hasil yang akan dilihat dari terminal output.
Andrew Henle

Jawaban:

21

Anda mungkin mendapatkan apa yang Anda butuhkan dengan menggunakan unbuffer.

unbufferadalah a tcl/ expectscript. Lihatlah sumbernya jika Anda mau. Perhatikan juga bagian CAVEATS pada manusia.

Perhatikan juga bahwa itu tidak mengeksekusi alias seperti:

alias ls='ls --color=auto'

kecuali ada yang menambahkan trik seperti dicatat oleh Stéphane Chazelas:

Jika Anda melakukan alias unbuffer='unbuffer '(perhatikan spasi tambahan), maka alias akan diperluas setelahnya unbuffer.

Runium
sumber
Catatan tentang alias yang diakui - juga tidak akan berfungsi dengan konstruksi shell lain seperti builtin dan fungsi.
Amir
4
Jika Anda melakukan alias unbuffer='unbuffer '(perhatikan spasi tambahan), maka alias akan diperluas setelahnya unbuffer.
Stéphane Chazelas
unbufferini! sudo apt install expect- Itu tidak jelas.
loxaxs
22

Sejarah toolets

Anda bukan orang pertama yang menginginkan alat seperti itu. Orang-orang telah menginginkan alat seperti itu selama 30 tahun. Dan mereka sudah ada hampir selama itu juga.

Alat paling awal untuk hal semacam ini adalah paket "pty" Daniel J. Bernstein, yang dijelaskan oleh Rich Salz sebagai "pisau Ginsu", yang ditulis Bernstein pada pergantian tahun 1990-an untuk menipu di nethack (sic!). Versi 4 dari paket "pty" diterbitkan pada tahun 1992 untuk comp.sources.unix(volume 25 masalah 127 hingga 135). Itu masih dapat ditemukan di World Wide Web. Paul Vixie menggambarkannya pada saat itu:

Apa yang bisa kukatakan? Mengiris, memotong dadu, mencuci piring, menuntun anjing. Ini "hanya bekerja", artinya jika Anda mengikuti petunjuk ini Anda akan mendapatkan paket kerja tanpa menarik rambut atau kertakan gigi atau kegiatan porting standar lainnya.

Bernstein kemudian memperbarui ini, sekitar atau sebelum 1999-04-07, dengan paket "ptyget", yang ia umumkan:

Saya telah mengumpulkan pengalokasi semu-tty baru, ptyget. Versi alfa berada di ftp://koobera.math.uic.edu/pub/software/ptyget-0.50.tar.gz. Ada milis ptyget; untuk bergabung, kirim pesan kosong ke [email protected]. Saya merancang antarmuka ptyget dari awal. Ini jauh lebih modular daripada pty; antarmuka pty dasar kini telah dibagi menjadi tiga bagian:

  • ptyget: program tingkat rendah yang kecil - satu-satunya program setuid dalam paket - yang mengalokasikan pseudo-tty baru dan meneruskannya ke program pilihan Anda
  • ptyspawn: program kecil lain yang menjalankan proses anak di bawah pseudo-tty, menunggu untuk keluar dan menonton berhenti
  • ptyio: program lain, hanya sedikit lebih besar, yang memindahkan data bolak-balik

Pisau Ginsu tua ptysekarang dieja ptybandage, yang merupakan sinonim untuk ptyget ptyio -t ptyspawn; pty -d, untuk melampirkan program jaringan ke pseudo-ttys, sekarang dieja ptyrun, yang merupakan sinonim untuk ptyget ptyio ptyspawn; dan nobufmerupakan sinonim untuk ptyget ptyio -r ptyspawn -23x. Saya telah membagi fitur manajemen sesi menjadi paket terpisah.

Paket terpisah itu adalah paket "sess".

"ptyget", secara kebetulan, terkenal karena mencontohkan versi yang sangat awal, dan salah satu dari sedikit contoh yang diterbitkan, sistem build "redo" buatan Berstein yang tidak pernah dipublikasikan. dependonadalah prekursor yang jelas untuk redo-ifchange.

Pemakaian

ptybandage

ptybandageadalah apa yang biasanya orang inginkan dalam sesi login. Kasus penggunaan utamanya adalah membuat program yang peka terhadap apakah input, output, atau kesalahan standar mereka terhubung ke terminal yang beroperasi seperti itu meskipun mereka sebenarnya dalam jaringan pipa shell, atau deskriptor file standarnya dialihkan ke file.

Dibutuhkan perintah untuk menjalankan (yang telah menjadi perintah eksternal yang tepat, tentu saja) dan berjalan itu sedemikian rupa sehingga berpikir bahwa standar input, output, dan kesalahan yang melekat pada terminal, menghubungkan mereka melalui ptybandage's input standar asli, keluaran, dan kesalahan.

Ini berurusan dengan nuansa berjalan di bawah cangkang kontrol pekerjaan, memastikan bahwa karakter STOP terminal tidak hanya berhenti ptybandagetetapi juga menghentikan program yang berjalan terpasang ke terminal bagian dalam.

ptyrun

ptyrunadalah apa yang biasanya orang inginkan di server jaringan TCP. Kasus penggunaan utamanya adalah lingkungan eksekusi jarak jauh yang belum mengatur terminal sendiri, menjalankan program yang tidak beroperasi seperti yang diinginkan ketika tidak ada terminal.

Itu tidak berharap untuk berjalan di bawah shell kontrol pekerjaan, dan jika perintah yang dijalankan menerima sinyal berhenti itu hanya restart.

Toolset yang tersedia

Dru Nelson menerbitkan "pty" versi 4 dan "ptyget".

Paul Jarc menerbitkan versi ptyget yang tetap, yang mencoba untuk berurusan dengan perangkat pseudo-terminal khusus sistem operasi ioctls di sistem asli yang sebenarnya tidak lagi disediakan oleh sistem operasi.

Paket source nosh dilengkapi dengan workalike ptybandangedan ptyrunskrip, yang menggunakan execlinealat Laurent Bercot dan perintah pseudo-terminal manajemen paket nosh itu sendiri. Pada nosh versi 1.23 ini tersedia pra-paket dalam paket nosh-terminal-ekstra. (Versi sebelumnya hanya menyediakannya untuk orang yang membangun dari sumber.)

Beberapa contoh menggunakan

Jurjgen Oskam menggunakan ptybandagepada AIX untuk memasukkan input dari dokumen di sini ke program yang terbuka dan membaca terminal pengendali untuk prompt kata sandi:

$ ptybandage dsmadmc << EOF> uit.txt
joskam
kata sandi
sesi permintaan
proses permintaan
berhenti
EOF

Andy Bradford menggunakan ptyrunOpenBSD di bawah daemontools dan ucspi-tcp untuk membuat bgplgshprogram kontrol router interaktif dapat diakses melalui jaringan sementara membuatnya berpikir bahwa itu berbicara ke terminal:

#! / bin / sh
exec 2> & 1
rv exec envuidgid tcpserver -vDRHl0 0 23 ptyrun / usr / bin / bgplgsh

Bacaan lebih lanjut

JdeBP
sumber
Terima kasih untuk pelajaran dalam sejarah, tetapi alat yang Anda sarankan tidak tersedia dalam distribusi Linux modern, karenanya tidak berguna.
Amir
4
Ada sekelompok hyperlink dan seluruh bagian dari jawaban yang ditujukan untuk mana alat yang paling pasti adalah tersedia.
JdeBP
1
Apa pendapat Anda expect?
CMCDragonkai
20

Anda dapat menggunakan socat untuk memulai proses Anda dengan pty terhubung, dan mendapatkan socat untuk menghubungkan ujung pty lain ke file. AFAIU mana yang persis Anda tanyakan:

socat EXEC:"my-command",pty GOPEN:mylog.log

Metode ini akan menyebabkan isattydipanggil oleh my-commanduntuk kembali truedan proses yang hanya bergantung pada yang akan tertipu untuk kode kontrol keluaran. Perhatikan bahwa beberapa proses (terutama grep) juga memeriksa nilai TERMvariabel lingkungan, jadi Anda mungkin perlu mengaturnya ke sesuatu yang masuk akal, seperti"xterm"

Guss
sumber
13

Ada juga solusi bagus yang diposting di sini di Super User oleh KarlC :

Kompilasi pustaka bersama kecil:

echo "int isatty(int fd) { return 1; }" | gcc -O2 -fpic -shared -ldl -o isatty.so -xc -

Kemudian beri tahu perintah Anda untuk memuat isatty(3)penggantian ini secara dinamis:

LD_PRELOAD=./isatty.so mycommand

Ini mungkin tidak bekerja untuk setiap perintah di luar sana, bahkan mungkin memecah beberapa dengan cara yang tidak terduga, tetapi mungkin akan bekerja dalam kebanyakan kasus.

Amir
sumber
2
Untuk pengguna MacOS, Anda bisa mendapatkan perilaku yang sama dengan menggunakanDYLD_INSERT_LIBRARIES=./isatty.so DYLD_FORCE_FLAT_NAMESPACE=y mycommand
Christopher Shroba
12

Bagaimana kalau menggunakan script(1)?

Sebagai contoh:

script -q -c 'ls -G' out_file

Akan menyimpan lsoutput out_filedengan kode warna dipertahankan.

sagi
sumber
Ini tidak berfungsi di sini. Bagaimana warna dipertahankan? Apakah ada alat yang harus saya gunakan untuk menampilkan out_filedengan warnanya?
Kira
1
@ Kirira untuk melihat file dengan urutan pelarian warna ANSI, saya gunakan less -R. Namun, dalam hal ini, saya ingin output berlanjut di dalam pipa, yang akhirnya berakhir di terminal saya. Menggunakan catuntuk ilustrasi, itu adalah sesuatu seperti script -q -c 'ls -G' /dev/null | cat, yang menekan typescriptfile sepenuhnya, hanya menyisakan output program.
Amir
Untuk menghindari membuat file, cukup gunakan tanda hubung ( -) sebagai scriptfile output, untuk contoh:script -q -c 'ls -G' -
Franklin Piat
0

Berdasarkan jawaban @ Amir , berikut adalah skrip yang menghasilkan dan kemudian menyertakan pustaka saat runtime:

#!/bin/bash
set -euo pipefail

function clean_up {
  trap - EXIT # Restore default handler to avoid recursion
  [[ -e "${isatty_so:-}" ]] && rm "$isatty_so"
}
# shellcheck disable=2154 ## err is referenced but not assigned
trap 'err=$?; clean_up; exit $err' EXIT HUP INT TERM

isatty_so=$(mktemp --tmpdir "$(basename "$0")".XXXXX.isatty.so)
echo "int isatty(int fd) { return 1; }" \
  | gcc -O2 -fpic -shared -ldl -o "$isatty_so" -xc -
# Allow user to SH=/bin/zsh faketty mycommand
"${SH:-$SHELL}" -c 'eval $@' - LD_PRELOAD="$isatty_so" "$@"
Tom Hale
sumber