Linux proc/pid/fd для stdout равен 11?

Выполнение сценария с перенаправлением stdout в файл. Таким образом, /proc/$$/fd/1 должен указывать на этот файл (поскольку stdout fileno равен 1). Однако фактический fd файла равен 11. Объясните, пожалуйста, почему.

Вот сессия:

$ cat hello.sh
#!/bin/sh -e
ls -l /proc/$$/fd >&2

$ ./hello.sh > /tmp/1
total 0
lrwx------ 1 nga users 64 May 28 22:05 0 -> /dev/pts/0
lrwx------ 1 nga users 64 May 28 22:05 1 -> /dev/pts/0
lr-x------ 1 nga users 64 May 28 22:05 10 -> /home/me/hello.sh
l-wx------ 1 nga users 64 May 28 22:05 11 -> /tmp/1
lrwx------ 1 nga users 64 May 28 22:05 2 -> /dev/pts/0

person stepancheg    schedule 28.05.2011    source источник
comment
что он делает, если вместо этого вы ls -l /proc/self/fd?   -  person Random832    schedule 28.05.2011


Ответы (2)


У меня есть подозрение, но это сильно зависит от поведения вашей оболочки. Дескрипторы файлов, которые вы видите:

  • 0: стандартный ввод
  • 1: стандартный вывод
  • 2: стандартная ошибка
  • 10: работающий скрипт
  • 11: резервная копия обычного стандартного выхода скрипта

Дескрипторы 10 и 11 близки в exec, поэтому не будут присутствовать в процессе ls. 0-2, однако, подготовлены для ls перед разветвлением. Я вижу такое поведение в dash (оболочка Debian Almquist), но не в bash (опять же оболочка Bourne). Вместо этого Bash выполняет манипуляции с файловым дескриптором после разветвления и, кстати, использует для сценария 255, а не 10. Выполнение изменения после разветвления означает, что ему не придется восстанавливать дескрипторы в родительском, поэтому у него нет запасной копии для dup2.

person Yann Vernier    schedule 28.05.2011
comment
Я понял, спасибо! Это действительно был тире, и bash и zsh показали правильное поведение. - person stepancheg; 28.05.2011
comment
Нет ничего неподобающего; это просто не так эффективно. Кроме того, это может быть необходимо для внутренних команд; bash может потребоваться больше логики для их обработки. - person Yann Vernier; 28.05.2011

Здесь могут быть полезны выходные данные strace.

Соответствующий раздел

fcntl64(1, F_DUPFD, 10)                 = 11
close(1)                                = 0
fcntl64(11, F_SETFD, FD_CLOEXEC)        = 0
dup2(2, 1)                              = 1
stat64("/home/random/bin/ls", 0xbf94d5e0) = -1 ENOENT (No such file or
+++++++>directory)
stat64("/usr/local/bin/ls", 0xbf94d5e0) = -1 ENOENT (No such file or directory)
stat64("/usr/bin/ls", 0xbf94d5e0)       = -1 ENOENT (No such file or directory)
stat64("/bin/ls", {st_mode=S_IFREG|0755, st_size=96400, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
+++++++>child_tidptr=0xb75a8938) = 22748
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 22748
--- SIGCHLD (Child exited) @ 0 (0) ---
dup2(11, 1)                             = 1

Таким образом, оболочка перемещает существующий стандартный вывод в доступный файловый дескриптор выше 10 (а именно, 11), затем перемещает существующий стандартный вывод в свой собственный стандартный вывод (из-за перенаправления >&2), затем восстанавливает 11 в свой собственный стандартный вывод при выполнении команды ls. законченный.

person Random832    schedule 28.05.2011