как перенаправление ввода работает?

На моем понимании, любая команда, которая читает из стандартного входа (т.е. клавиатура), что это получает свой вход из файла.

$echo < text_content.txt

$

Но команда эха не читает и отображает text_content.txt на терминале. что случилось здесь?

2
задан 23 February 2019 в 10:25

1 ответ

stdin и Команды

На моем понимании, любая команда, которая читает из стандартного входа (т.е. клавиатура), что это получает свой вход из файла.

Эффективно, да. Как я обсудил в своем ответе на том, Что характеризует файл в Linux/Unix?, файл является любым объектом, на котором можно выполнить стандартные операции такой как read(), open(), write(), close(). stdin быть представленным через дескриптор файла 0 является эффективно файлом в том отношении, и любая команда/процесс в Linux получает 3 стандартных дескрипторов файлов - stdin, stdout, stderr - когда тот процесс запускается. Каковы фактические файлы позади тех дескрипторов файлов? Команда не заботится, и не был должен, пока она может сделать операции на нем.

Но команда эха не читает и отображает text_content.txt на терминале. что случилось здесь?

Теперь, команда является бесплатной сделать то, что она будет с теми файл descriptors1. В случае echo это только имеет дело с stdout и не выполняет действия с stdin вообще. Таким образом, нет ничего неправильно с самой командой.

< перенаправление будет open() файл text_content.txt для чтения, и это все еще присвоится, дескриптор файла (например, 3) возвратился из open() звоните в дескриптор файла 0, и если команда будет касаться stdin то - это будет читать из дескриптора файла 0, как будто ничего не произошло. На самом деле Вы будете видеть, что в действии, если Вы будете работать strace -f -e dup2,write,openat bash -c 'echo < text_content.txt

openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
dup2(3, 0)                              = 0
write(1, "\n", 1
)                       = 1
dup2(10, 0)                             = 0
+++ exited with 0 +++

Заметьте dup2() системный вызов. Это - то, как дескриптор файла 3 (файл) присвоен/перенаправлен. В виде cp original copy синтаксис, dup2(3,0) делает копию дескриптора файла 3 к дескриптору файла 0, и они указывают на тот же файл.

Заметьте также это write() произведите новую строку к дескриптору файла 1. Это - поведение по умолчанию. Если мы делаем strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' вот то, что мы будем видеть

dup2(3, 0)                              = 0
write(1, "FOO\n", 4FOO
)                    = 4
dup2(10, 0)                             = 0
+++ exited with 0 +++

Таким образом, снова ничто неправильно здесь - перенаправления не выполняется правильно и echo делает его задание записи материала к stdout который является дескриптором файла 1.


Как на самом деле считать файл

Теперь, позволяет, обращаются к чему-то еще. Как мы можем считать файл в оболочке? Ну, для этого там существует cat команда, которая принимает аргументы, таким образом, можно сделать просто cat file.txt. Можно ли сделать cat < file.txt ?Конечно. Но это означает, что оболочка должна будет сделать это dup2() звоните, тогда как cat file.txt не делает - таким образом, существует менее ненужный syscalls, то, что я говорю.

В сложных случаях, такой как тогда, когда необходимо выполнить действие с каждой строкой файла, Вы сделали бы

while IFS= read -r line || [ -n "$line" ]; do
    # command to process line variable here
done < /etc/passwd

Теперь, для целого дескриптора файла цикла 0 будет копия любого дескриптора файла, возвращается из открытия /etc/passwd. Конечно, если можно использовать cat или другая определенная команда к заданию чтения файла - делает это. Shell является медленным методом и имеет много ловушек. См. также, Почему использование является циклом оболочки к тексту процесса, который рассматривают плохой практикой?


1. Некоторые приложения все еще могли бы заботиться о том, что они могут сделать с stdin или обнаружить, если stdin является файлом или конвейером. Когда stdin дескриптор файла назначен концом чтения конвейера (который является также дескриптором файла), вывод не seekable (подразумевать, что приложение, записанное в C или другом языке, не может использовать seek() syscall для быстрой навигации к определенному байтовому смещению в файле). Хороший пример этого дан в вопросе, названном, Каково различие между “файлом кошки |./двоичный файл” и “./двоичный файл <файл”?

Заметка на полях: на Linux это не точно клавиатура от того, где stdin получает свой вход. Если Вы делаете

$ ls -l /proc/self/fd/0
lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0

Вы будете видеть в выводе, что это /dev/pts/0 оконечное устройство, к который stdin точки первоначально. Оконечное устройство затем взаимодействует через интерфейс с клавиатурой, или это мог также быть последовательный кабель.

Кроме того, если файл не является очень большим, Вы могли бы использовать в своих интересах bash mapfile встроенный для чтения строк в массив:

mapfile  -t  < /etc/passwd
for i in "${MAPFILE[@]}"; do echo "$i"; done

3
ответ дан 2 December 2019 в 02:40

Другие вопросы по тегам:

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