尽管托马斯·迪基的答案很正确,但斯特凡·查泽拉斯在对迪基的答案的评论中正确地提到,这种转变不是一成不变的。它是生产线学科的一部分。
实际上,翻译是完全可编程的。
在男子3周的termios手册页基本上包含所有相关信息。(该链接指向Linux手册页项目,该项目确实提到了仅Linux的功能,以及POSIX或其他系统所共有的功能;请始终检查那里每个页面的“ 符合”部分。)
所述iflag
终端属性(old_settings[0]
在问题中所示的代码的Python)具有对所有POSIXy系统三个相关国旗:
INLCR
:如果设置,则将输入上的NL转换为CR
ICRNL
:如果已设置(IGNCR
且未设置),则将输入上的CR转换为NL
IGNCR
:忽略输入的CR
同样,也有相关的输出设置(old_settings[1]
):
OPOST
:启用输出处理。
OCRNL
:在输出上将CR映射到NL。
ONLCR
:将NL映射到输出的CR。(XSI;并非在所有POSIX或Single-Unix-Specification系统中都可用。)
ONOCR
:跳过(不输出)第一栏中的CR。
ONLRET
:跳过(不输出)CR。
例如,您可以避免依赖该tty
模块。“ makeraw”操作仅清除一组标志(并设置CS8
offlag):
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
尽管出于兼容性考虑,您可能希望首先检查termios模块中是否存在所有这些常量(如果在非POSIX系统上运行)。您还可以使用new_settings[6][termios.VMIN]
和new_settings[6][termios.VTIME]
设置是否在没有待处理数据的情况下阻止读取,以及设置多长时间(以整数秒为单位)。(通常VMIN
设置为0,VTIME
如果读取应立即返回,则设置为0,或者设置为正数(十分之一秒),读取最多应等待多长时间。)
如您所见,以上内容(通常是“ makeraw”)会禁用输入的所有翻译,这说明了cat的行为:
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IGNCR
为了获得正常的行为,只需省略清除这三行的行,即使“原始”,输入的翻译也保持不变。
该new_settings[1] = new_settings[1] & ~termios.OPOST
行将禁用所有输出处理,无论其他输出标志怎么说。您可以忽略它以保持输出处理完好无损。这样即使在原始模式下也可以保持输出“正常”。(它不会影响是否自动回显输入;这由中的ECHO
cflag 控制new_settings[3]
。)
最后,设置了新属性后,如果设置了任何新设置,则调用将成功。如果设置敏感(例如,如果您在命令行中要求输入密码),则应获取新设置,并确认正确设置/取消了重要标志。
如果要查看当前的终端设置,请运行
stty -a
如果未设置标志,则输入标志通常在第四行,输出标志在第五行,并-
在标志名之前。例如,输出可能是
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
在伪终端和USB TTY设备上,波特率无关。
如果编写希望读取例如密码的Bash脚本,请考虑以下习惯用法:
#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0
在EXIT
每当外壳退出执行陷阱。stty -g
在脚本开始时,读取操作将读取终端的当前设置,因此在脚本退出时会自动恢复当前设置。您甚至可以使用Ctrl+ 中断脚本C,它将做正确的事。(在某些有信号的极端情况下,我发现终端有时会卡在原始/非规范的设置上(要求在终端上盲目地键入reset
+ Enter),但是stty sane
在恢复实际的原始设置之前运行可以解决每次我。这就是为什么它在那里;一种额外的安全性。)
您可以使用read
内置的bash 读取输入行(未在终端上显示),甚至可以使用逐字符读取输入
IFS=$'\0'
input=""
while read -N 1 c ; do
[[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
input="$input$c"
done
如果未设置IFS
为ASCII NUL,则read
内置函数将使用分隔符,因此c
将为空。年轻球员的陷阱。