Давайте посмотрим на пример с некоторым тщательно созданным входным текстом:
text=' hello world\
foo\bar'
Это - две строки, первое начало с пространства и окончание обратной косой чертой. Во-первых, давайте посмотрим на то, что происходит без любых мер предосторожности вокруг read
(но использование printf '%s\n' "$text"
тщательно распечатать $text
без любого риска расширения). (Ниже, $
приглашение оболочки.)
$ printf '%s\n' "$text" |
while read line; do printf '%s\n' "[$line]"; done
[hello worldfoobar]
read
съел обратные косые черты: новая строка обратной косой черты заставляет новую строку быть проигнорированной, и обратная косая черта - что-либо игнорирует ту первую обратную косую черту. Для предотвращения обратных косых черт, которые рассматривают особенно, мы используем read -r
.
$ printf '%s\n' "$text" |
while read -r line; do printf '%s\n' "[$line]"; done
[hello world\]
[foo\bar]
Это лучше, у нас есть две строки как ожидалось. Эти две строки почти содержат желаемое содержание: двойной интервал между hello
и world
был сохранен, потому что это в line
переменная. С другой стороны, начальное пространство было съедено. Поэтому read
отбрасываются чтения столько слов, сколько Вы передаете его переменные, за исключением того, что последняя переменная содержит остальную часть строки — но это все еще запускается с первого слова, т.е. начальных пробелов.
Так, для чтения каждой строки буквально, мы должны удостовериться, что никакое разделение слова не продолжается. Мы делаем это путем установки IFS
переменная к пустому значению.
$ printf '%s\n' "$text" |
while IFS= read -r line; do printf '%s\n' "[$line]"; done
[ hello world\]
[foo\bar]
Отметьте, как мы устанавливаем IFS
специально для продолжительности read
встроенный. IFS= read -r line
устанавливает переменную среды IFS
(к пустому значению) специально для выполнения read
. Это - экземпляр общего простого синтаксиса команды: (возможно пустой) последовательность переменных присвоений, сопровождаемых названием команды и его аргументами (также, можно добавить перенаправления в любой точке). С тех пор read
встроенное, переменная никогда на самом деле заканчивается в среде внешнего процесса; тем не менее, значение $IFS
то, что мы присваиваем там пока read
выполняет ¹. Отметьте это read
не встроенное специальное предложение, таким образом, присвоение действительно только продолжается в свой период.
Таким образом мы заботимся для не изменения значения IFS
для других инструкций, которые могут полагаться на него. Этот код будет работать независимо от того, что установил окружающий код IFS
к первоначально, и это не доставит неприятностей, если код в цикле будет полагаться IFS
.
Контраст с этим фрагментом кода, который ищет файлы в разделенном от двоеточия пути. Список имен файлов прочитан из файла, одно имя файла на строку.
IFS=":"; set -f
while IFS= read -r name; do
for dir in $PATH; do
## At this point, "$IFS" is still ":"
if [ -e "$dir/$name" ]; then echo "$dir/$name"; fi
done
done
Если цикл был while IFS=; read -r name; do …
, затем for dir in $PATH
не разделил бы $PATH
в разделенные от двоеточия компоненты. Если код был IFS=; while read …
, это было бы еще более очевидно это IFS
не установлен на :
в теле цикла.
Конечно, было бы возможно восстановить значение IFS
после выполнения read
. Но это потребовало бы знания предыдущего значения, которое является дополнительным усилием. IFS= read
простой путь (и, удобно, также самый короткий путь).
¹ И, если read
прерван захваченным сигналом, возможно в то время как прерывание выполняется — это не указано POSIX и зависит от оболочки на практике.
При нажатии клавиши на клавиатуре она отправляет цифровой код на компьютер, названный скэн-кодом. Скэн-код говорит компьютер, какая клавиша была нажата; например, на типичной американской клавиатуре, ключ отправляет скэн-код 30 при нажатии его (и 158 при выпуске его). Драйвер клавиатуры сообщает об этих кодах непосредственно приложениям, когда клавиатура находится в режиме без предварительной обработки (“сырые данные” означают необработанный, непосредственно-клавиатура). Несколько программ используют режим без предварительной обработки и делают их собственную обработку клавиатуры; X-сервер является самым видным.
Большинство программ ожидает, что при нажатии клавиши программа читает символ a
(ASCII 97) и это, когда Вы нажимаете Shift+A чтения программы A
(ASCII 65), и когда Вы нажимаете Ctrl+A программа, читает Ctrl+A
символ (ASCII 1). Ключи, которые не имеют связанных символов, отправляют escape-последовательности, например. \e[A
для Левого, где \e
символ ESC (ASCII 27). Драйвер клавиатуры выполняет этот перевод, когда клавиатура находится в режиме ASCII, также названный режимом XLATE (короткий для “переводят”). Режим XLATE позволяет приложениям сделать ввод символов, за счет не наличия доступа к таким нюансам как “Клавиша сдвига влево, нажатая” или Ctrl+Shift+A в отличие от Ctrl+A.
kbd_mode
позволяет Вам переключиться между режимами и показывает текущий режим, если Вы вызываете его без какого-либо аргумента.
Волшебные сочетания клавиш SysRq предназначены для восстановления с различных противных ситуаций. Одно из сочетаний клавиш Alt+SysRq+K
закрыть все программы на текущей виртуальной консоли; если та программа поместит клавиатуру в режим без предварительной обработки, то Вы не сможете ввести при приглашении ко входу в систему (который будет часто появляться, в зависимости от Вашей конфигурации системы). Нажатие Alt+SysRq+R
восстанавливает обычное (вне X) режим ASCII, где можно ввести символы.
Можно определить, какой тип кода клавиатура отправляет. Это сделано через режим ввода с клавиатуры. Можно изменить режим клавиатуры с kbd_mode
.
Это опции из страницы справочника:
-s: scancode mode (RAW),
-k: keycode mode (MEDIUMRAW),
-a: ASCII mode (XLATE),
-u: UTF-8 mode (UNICODE).
Его намного более легкое для разработчика для ловли ключевых событий как нажатая клавиша сдвига влево, если он может просто получить scancodes нажатых клавиш.