Sementara jawaban Thomas Dickey cukup benar, Stéphane Chazelas dengan benar disebutkan dalam komentar atas jawaban Dickey bahwa pertobatannya tidak dilakukan dengan keras; itu adalah bagian dari garis disiplin.
Bahkan, terjemahannya sepenuhnya dapat diprogram.
Halaman manual man 3 termios pada dasarnya berisi semua informasi terkait. (Tautan ke proyek man-pages Linux , yang menyebutkan fitur mana yang hanya Linux, dan yang umum untuk POSIX atau sistem lain; selalu periksa bagian Menyesuaian untuk pada setiap halaman di sana.)
The iflag
atribut terminal ( old_settings[0]
dalam kode yang ditunjukkan di pertanyaan di Python ) memiliki tiga bendera yang relevan pada semua sistem POSIXy:
INLCR
: Jika diatur, terjemahkan NL ke CR pada input
ICRNL
: Jika diatur (dan IGNCR
tidak diatur), terjemahkan CR ke NL pada input
IGNCR
: Abaikan CR pada input
Demikian pula, ada pengaturan keluaran terkait ( old_settings[1]
), juga:
OPOST
: Aktifkan pemrosesan keluaran.
OCRNL
: Peta CR ke NL pada output.
ONLCR
: Peta NL ke CR pada output. (XSI; tidak tersedia di semua sistem POSIX atau Single-Unix-Specification.)
ONOCR
: Lewati (jangan keluaran) CR di kolom pertama.
ONLRET
: Lewati (jangan keluaran) CR.
Misalnya, Anda dapat menghindari mengandalkan tty
modul. Operasi "makeraw" hanya membersihkan satu set bendera (dan mengatur CS8
oflag):
import sys
import termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
ch = None
try:
new_settings = termios.tcgetattr(fd)
new_settings[0] = new_settings[0] & ~termios.IGNBRK
new_settings[0] = new_settings[0] & ~termios.BRKINT
new_settings[0] = new_settings[0] & ~termios.PARMRK
new_settings[0] = new_settings[0] & ~termios.ISTRIP
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.IGNCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IXON
new_settings[1] = new_settings[1] & ~termios.OPOST
new_settings[2] = new_settings[2] & ~termios.CSIZE
new_settings[2] = new_settings[2] | termios.CS8
new_settings[2] = new_settings[2] & ~termios.PARENB
new_settings[3] = new_settings[3] & ~termios.ECHO
new_settings[3] = new_settings[3] & ~termios.ECHONL
new_settings[3] = new_settings[3] & ~termios.ICANON
new_settings[3] = new_settings[3] & ~termios.ISIG
new_settings[3] = new_settings[3] & ~termios.IEXTEN
termios.tcsetattr(fd, termios.TCSANOW, new_settings)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
meskipun demi kompatibilitas, Anda mungkin ingin memeriksa apakah semua konstanta itu ada di modul termios terlebih dahulu (jika Anda menjalankan sistem non-POSIX). Anda juga dapat menggunakan new_settings[6][termios.VMIN]
dan new_settings[6][termios.VTIME]
untuk mengatur apakah pembacaan akan memblokir jika tidak ada data yang tertunda, dan berapa lama (dalam bilangan bulat deciseconds). (Biasanya VMIN
diatur ke 0, dan VTIME
ke 0 jika bacaan harus segera kembali, atau ke angka positif (sepersepuluh detik) berapa lama bacaan paling banyak menunggu.)
Seperti yang Anda lihat, di atas (dan "makeraw" secara umum) menonaktifkan semua terjemahan pada input, yang menjelaskan perilaku yang dilihat kucing:
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IGNCR
Untuk mendapatkan perilaku normal, cukup hapus baris yang menghapus ketiga baris tersebut, dan terjemahan input tidak berubah bahkan ketika "mentah".
The new_settings[1] = new_settings[1] & ~termios.OPOST
garis menonaktifkan semua proses output, terlepas apa bendera keluaran lain mengatakan. Anda bisa menghilangkannya agar proses pemrosesan output tetap utuh. Ini membuat output "normal" bahkan dalam mode mentah. (Itu tidak mempengaruhi apakah input secara otomatis digaungkan atau tidak; yang dikendalikan oleh ECHO
cflag in new_settings[3]
.)
Akhirnya, ketika atribut baru diatur, panggilan akan berhasil jika ada pengaturan baru yang ditetapkan. Jika pengaturannya sensitif - misalnya, jika Anda meminta kata sandi pada baris perintah -, Anda harus mendapatkan pengaturan baru, dan memverifikasi bahwa tanda-tanda penting sudah diatur / tidak disetel dengan benar, untuk memastikan.
Jika Anda ingin melihat pengaturan terminal Anda saat ini, jalankan
stty -a
Bendera input biasanya di baris keempat, dan bendera output di baris kelima, dengan -
mendahului nama bendera jika bendera tidak disetel. Misalnya, outputnya bisa
speed 38400 baud; rows 58; columns 205; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Pada pseudoterminals, dan perangkat USB TTY, baud rate tidak relevan.
Jika Anda menulis skrip Bash yang ingin dibaca misalnya kata sandi, pertimbangkan idiom berikut:
#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0
The EXIT
perangkap dijalankan setiap kali shell keluar. The stty -g
membaca pengaturan saat ini terminal pada awal script, sehingga pengaturan saat dikembalikan ketika keluar skrip, secara otomatis. Anda bahkan dapat mengganggu skrip dengan Ctrl+ C, dan itu akan melakukan hal yang benar. (Dalam beberapa kasus sudut dengan sinyal, saya telah menemukan bahwa terminal kadang-kadang macet dengan pengaturan mentah / noncanonical (memerlukan satu untuk mengetik reset
+ Entersecara membabi buta di terminal), tetapi berjalan stty sane
sebelum mengembalikan pengaturan asli yang sebenarnya telah sembuh bahwa setiap kali untuk saya. Jadi itu sebabnya ada di sana; semacam keamanan tambahan.)
Anda dapat membaca jalur input (tidak bertanda ke terminal) menggunakan read
bash built-in, atau bahkan membaca input karakter demi karakter menggunakan
IFS=$'\0'
input=""
while read -N 1 c ; do
[[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
input="$input$c"
done
Jika Anda tidak disetel IFS
ke ASCII NUL, read
built-in akan mengkonsumsi separator, sehingga c
akan kosong. Perangkap untuk pemain muda.