Trong khi câu trả lời của Thomas Dickey hoàn toàn chính xác, Stéphane Chazelas đã đề cập chính xác trong một bình luận cho câu trả lời của Dickey rằng việc chuyển đổi không được đặt trong đá; nó là một phần của kỷ luật dòng
Trong thực tế, bản dịch là hoàn toàn lập trình.
Trang man 3 termios chứa cơ bản tất cả các thông tin thích hợp. (Liên kết đưa đến dự án trang người dùng Linux , trong đó đề cập đến các tính năng chỉ dành cho Linux và phổ biến cho POSIX hoặc các hệ thống khác; luôn kiểm tra phần Tuân thủ theo từng trang ở đó.)
Các iflag
thuộc tính đầu cuối ( old_settings[0]
trong mã được hiển thị trong câu hỏi trong Python ) có ba cờ có liên quan trên tất cả các hệ thống POSIXy:
INLCR
: Nếu được đặt, dịch NL sang CR trên đầu vào
ICRNL
: Nếu được đặt (và IGNCR
không được đặt), hãy dịch CR sang NL trên đầu vào
IGNCR
: Bỏ qua CR trên đầu vào
Tương tự, cũng có các cài đặt đầu ra liên quan ( old_settings[1]
):
OPOST
: Cho phép xử lý đầu ra.
OCRNL
: Ánh xạ CR tới NL trên đầu ra.
ONLCR
: Ánh xạ NL tới CR trên đầu ra. (XSI; không khả dụng trong tất cả các hệ thống POSIX hoặc Single-Unix.)
ONOCR
: Bỏ qua (không xuất) CR trong cột đầu tiên.
ONLRET
: Bỏ qua (không xuất) CR.
Ví dụ, bạn có thể tránh dựa vào tty
mô-đun. Hoạt động "Makeraw" chỉ xóa một bộ cờ (và đặt 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
mặc dù vì mục đích tương thích, bạn có thể muốn kiểm tra xem tất cả các hằng số đó có tồn tại trong mô đun termios hay không (nếu bạn chạy trên các hệ thống không phải POSIX). Bạn cũng có thể sử dụng new_settings[6][termios.VMIN]
và new_settings[6][termios.VTIME]
để đặt xem liệu một lần đọc sẽ chặn nếu không có dữ liệu đang chờ xử lý và thời gian (tính theo số nguyên của số giây). (Thông thường VMIN
được đặt thành 0 và VTIME
thành 0 nếu các lần đọc sẽ quay lại ngay lập tức hoặc về một số dương (một phần mười giây) thời gian đọc nên chờ tối đa.)
Như bạn có thể thấy, nói chung (và "hãng sản xuất" nói chung) vô hiệu hóa tất cả các bản dịch trên đầu vào, điều này giải thích hành vi mà mèo đang nhìn thấy:
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IGNCR
Để có được hành vi bình thường, chỉ cần bỏ qua các dòng xóa ba dòng đó và bản dịch đầu vào không thay đổi ngay cả khi "thô".
Các new_settings[1] = new_settings[1] & ~termios.OPOST
dòng vô hiệu hóa tất cả các xử lý đầu ra, bất kể những gì những lá cờ đầu ra khác nói. Bạn chỉ có thể bỏ qua nó để giữ nguyên xử lý đầu ra. Điều này giữ cho đầu ra "bình thường" ngay cả trong chế độ thô. (Nó không ảnh hưởng đến việc liệu đầu vào có tự động lặp lại hay không; điều đó được điều khiển bởi ECHO
cflag trong new_settings[3]
.)
Cuối cùng, khi các thuộc tính mới được đặt, cuộc gọi sẽ thành công nếu bất kỳ cài đặt mới nào được đặt. Nếu cài đặt nhạy cảm - ví dụ: nếu bạn đang yêu cầu nhập mật khẩu trên dòng lệnh -, bạn nên lấy cài đặt mới và xác minh các cờ quan trọng được đặt / bỏ đặt chính xác, để chắc chắn.
Nếu bạn muốn xem cài đặt thiết bị đầu cuối hiện tại của mình, hãy chạy
stty -a
Các cờ đầu vào thường nằm trên dòng thứ tư và các cờ đầu ra trên dòng thứ năm, với -
tên cờ trước nếu cờ không được đặt. Ví dụ: đầu ra có thể là
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
Trên giả hành và các thiết bị USB TTY, tốc độ truyền không liên quan.
Nếu bạn viết các tập lệnh Bash muốn đọc ví dụ mật khẩu, hãy xem xét thành ngữ sau:
#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0
Cái EXIT
bẫy được thực hiện bất cứ khi nào vỏ thoát ra. Việc stty -g
đọc các cài đặt hiện tại của thiết bị đầu cuối khi bắt đầu tập lệnh, vì vậy các cài đặt hiện tại sẽ được khôi phục khi tập lệnh thoát, tự động. Bạn thậm chí có thể làm gián đoạn tập lệnh bằng Ctrl+ Cvà nó sẽ làm đúng. (Trong một số trường hợp góc có tín hiệu, tôi thấy rằng thiết bị đầu cuối đôi khi bị kẹt với cài đặt thô / phi núi (yêu cầu một thiết bị gõ reset
+ Entermù ở thiết bị đầu cuối), nhưng chạy stty sane
trước khi khôi phục cài đặt gốc thực tế đã chữa khỏi mọi lúc tôi. Vậy đó là lý do tại sao nó ở đó; một loại an toàn bổ sung.)
Bạn có thể đọc các dòng đầu vào (chưa được gắn vào thiết bị đầu cuối) bằng cách sử dụng read
bash tích hợp hoặc thậm chí đọc từng ký tự đầu vào bằng cách sử dụng
IFS=$'\0'
input=""
while read -N 1 c ; do
[[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
input="$input$c"
done
Nếu bạn không được đặt IFS
thành ASCII NUL, tích read
hợp sẽ tiêu thụ các dấu phân cách, do đó c
sẽ trống. Bẫy cho các cầu thủ trẻ.