Ошибка перенаправления файла Bash?

Из того, что я понимаю о программе IO, существует stdin, stdout, и stderr потоки данных (и код возврата). stdout и stderr два потока вывода данных. Таким образом, если я использую перенаправление удара для закрытия одного из потоков вывода, я могу сузить, какой поток, в который отправляется текст.Правильно?

Я запускаю Ubuntu 18.04.1 LTS, и я сталкиваюсь с этой причудливой проблемой с перенаправлением удара.

Позвольте мне объяснить пример. Вот моя команда:

# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found
# |

php5 пакет не существует на Ubuntu 18.04 так apt-cache отображает ошибку. Я предположил бы, что этот текст отправляется в stderr поток, таким образом, я попытался закрыть тот поток:

# apt-cache show php5 2>&-
# |

Кажется, что это проверяет, что текст был отправлен через stderr. Вся польза до сих пор! Но теперь как проверка работоспособности, я пытался закрыться stdout (Я должен видеть текст ошибки теперь):

# apt-cache show php5 1>&-
# |

Что!? Я перенаправил stdout на этот раз, но stderr также не обнаруживается?

Согласно Интернету, у меня есть свои корректные дескрипторы файлов: https://www.gnu.org/software/bash/manual/html_node/Redirections.html

Я не могу выяснить то, что могло продолжаться здесь.

Доказательство снимка экрана:

Bash redirect bug

3
задан 6 October 2018 в 05:33

1 ответ

TL; DR: Это не bash, это apt-cache, что возиться с файловыми дескрипторами.

apt-cache делает что-то очень интересное - это не выдает строки, начинающиеся с N: символов, предназначенных для stdout.

Рассмотрим это:

$ apt-cache show nonexistent
N: Unable to locate package nonexistent
E: No packages found

Мы видим две строки, одна из которых начинается с N:, другая начинается с E:. N: строки идут на стандартный вывод. В вашем примере у вас есть две N: строки.

# apt-cache show php5
N: Can't select versions from package 'php5' as it is purely virtual
N: No packages found

Если вы проследите системные вызовы через strace -e write -f bash -c 'apt-cache show randomtext >&-', вы увидите, что запись E: строк происходит, но N строк там нет:

[pid 12450] write(2, "E", 1E)            = 1
[pid 12450] write(2, ": ", 2: )           = 2
[pid 12450] write(2, "No packages found", 17No packages found) = 17
[pid 12450] write(2, "\n", 1
)           = 1
[pid 12450] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12450, si_uid=1000, si_status=100, si_utime=5, si_stime=2} ---
+++ exited with 100 +++

Итак apt-cache ] достаточно умен, чтобы проверить перенаправленный стандартный вывод. Но как насчет stderr? Видимо, записи все еще здесь: если вы сделаете strace -e write,openat,dup2 -f bash -c 'apt-cache show randomtext 2>&-, вы увидите, что apt-cache открывает /dev/null, чтобы еще что-то присутствовать для stderr:

[pid 12543] openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 2
....
[pid 12543] write(2, "N", 1)            = 1
[pid 12543] write(2, ": ", 2)           = 2
[pid 12543] write(2, "Unable to locate package randomt"..., 35) = 35
[pid 12543] write(2, "\n", 1)           = 1
[pid 12543] write(2, "E", 1)            = 1
[pid 12543] write(2, ": ", 2)           = 2
[pid 12543] write(2, "No packages found", 17) = 17
[pid 12543] write(2, "\n", 1)           = 1
[pid 12543] +++ exited with 100 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12543, si_uid=1000, si_status=100, si_utime=5, si_stime=3} ---
+++ exited with 100 +++

То же самое с другими программами в bash, работает как положено:

# stdout closed, stderr not
$ ls -l /proc/self/fd >&-
ls: write error: Bad file descriptor
# stdout open , stderr closed, and it's number is assigned to whatever command is trying to open - in this case /proc/self/fd directory
$ ls -l /proc/self/fd 2>&-
total 0
lrwx------ 1 xie xie 64 Oct  6 11:32 0 -> /dev/pts/1
lrwx------ 1 xie xie 64 Oct  6 11:32 1 -> /dev/pts/1
lr-x------ 1 xie xie 64 Oct  6 11:32 2 -> /proc/12723/fd
3
ответ дан 1 December 2019 в 16:16

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

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