На моем понимании, любая команда, которая читает из стандартного входа (т.е. клавиатура), что это получает свой вход из файла.
$echo < text_content.txt
$
Но команда эха не читает и отображает text_content.txt на терминале. что случилось здесь?
На моем понимании, любая команда, которая читает из стандартного входа (т.е. клавиатура), что это получает свой вход из файла.
Эффективно, да. Как я обсудил в своем ответе на том, Что характеризует файл в 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