Получить разрешения и объединить их в одну строку

Хотя ответ Томаса Дики совершенно верен, Стефан Шазелас правильно отметил в комментарии к ответу Дики, что преобразование не является чем-то неизменным; это часть линейной дисциплины.

На самом деле, перевод полностью программируется.

Страница man 3 termios man содержит практически всю необходимую информацию. (Ссылка ведет на Linux man-pages project, где упоминается, какие функции присущи только 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 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

хотя ради совместимости, возможно, вы захотите сначала проверить, существуют ли все эти константы в модуле termios (если вы работаете на системах не-POSIX). Вы также можете использовать new_settings[6][termios.VMIN] и new_settings[6][termios.VTIME], чтобы установить, будет ли чтение блокироваться, если нет ожидающих данных, и как долго (в целых числах децисекунд). (Обычно VMIN устанавливается в 0, а VTIME в 0, если чтение должно вернуться немедленно, или в положительное число (десятые доли секунды), сколько времени чтение должно ждать максимум).

Как вы можете видеть, вышеуказанное (и "makeraw" в целом) отключает всю трансляцию на вводе, что объясняет поведение, наблюдаемое котом:

    new_settings[0] = new_settings[0] & ~termios.INLCR
    new_settings[0] = new_settings[0] & ~termios.ICRNL
    new_settings[0] = new_settings[0] & ~termios.IGNCR

Чтобы получить нормальное поведение, просто опустите строки, очищающие эти три строки, и трансляция ввода не изменится даже при "raw".

Строка new_settings[1] = new_settings[1] & ~termios.OPOST отключает всю обработку вывода, независимо от того, что говорят другие флаги вывода. Вы можете просто опустить ее, чтобы сохранить обработку вывода без изменений. Это сохраняет вывод "нормальным" даже в режиме raw. (Это не влияет на то, будет ли ввод автоматически эхом или нет; это контролируется 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 будет пустым. Ловушка для молодых игроков.

0
23.03.2019, 21:54
2 ответа

Первый символ можно удалить с помощьюcut -c 2-

ls -l | tail -n+2 | cut -d" " -f1 | cut -c 2- | tr -d '\n'
1
28.01.2020, 02:22

lsимеет очень плохие возможности форматирования. statимеет опцию --printfдля форматирования необходимой информации о файлах.

пример:

root@linux:~# stat --printf  '%A\n' /etc/passwd /etc
-rw-r--r--
drwxr-xr-x

в случае тура, потому что вы не первый символ

root@linux:~# stat --printf  '%A\n' file*  | cut -c2-11 | tr -d '\n'
2
28.01.2020, 02:22

Теги

Похожие вопросы