Почему чтение работает, если stdin перенаправлен на fd4?

Почему чтение работает, если stdin перенаправлен на fd4?

Что означает следующий сценарий?

exec 4<&0 0</etc/XX/cfg
read line1
exec 0<&4

Он перенаправляет fd0 на fd4, а «/etc/XX/cfg» на fd0.

Так почему же он readвсе еще работает, разве он не должен быть пустым?

решение1

Он перенаправляет stdin (FD0) на FD4, перенаправляет с /etc/XX/cfgна FD0, считывает строку из FD0, а затем перемещает FD4 обратно на FD0. Короче говоря, он сохраняет, заменяет и восстанавливает stdin, считывая строку из файла между этим.

read line1 < /etc/XX/cfgбыло бы намного проще, но невозможно определить, является ли это допустимой заменой, основываясь только на показанном коде.

решение2

Чтобы перевести это в системные вызовы (используя C):

exec 4<&0 0</etc/XX/cfg

/* Duplicate fd0 as fd4.  */
dup2 (0, 4);

/* Open file on fd0.
   "open" always uses lowest available descriptor, so we don't need to check it. */
close (0);
open ("/etc/XX/cfg", O_RDONLY);

exec 0<&4

/* Close fd0 and duplicate fd4 as fd0.  */
dup2 (4, 0);

решение3

Насколько я понимаю это (основываясь на разделе man-страницы bash о ПЕРЕНАПРАВЛЕНИИ), stdin(fd0) перенаправляется в fd4, затем из него берется ввод /etc/XX/cfg, stdinкоторый в конечном итоге попадает на fd4.

read line1затем следует взять из fd4, который затем поместить обратно в fd0.

Демонстрация могла бы показать мой смысл немного лучше и ответить на вопрос «почему» вы могли бы это сделать. Добавив еще одну строку и поместив ее в обертку:

$ vim ./test.sh
#!/bin/bash
exec 4<&0 0</etc/XX/cfg
read line1    # reads from fd4
exec 0<&4
read line2    # reads from fd0

echo $line1 
echo $line2

Вы можете передавать данные по конвейеру или перенаправлять их stdinчерез test.sh, но также можете читать конфигурацию с помощью перенаправления, поэтому в коде выше я извлек значения из «config» (предположение с моей стороны, основанное на имени файла — плохое :) ), но я также могу обрабатывать данные через stdin.

например:

$ ./test.sh < somefile
$ cat somefile | ./test.sh

Надеюсь, это все объясняет.

Связанный контент