Программа Bash не выполняется, если перенаправление не удастся


9

В bash я заметил, что если команда, использующая перенаправление, потерпит неудачу, любые программы, которые выполняются до этого, не запускаются.

Например, эта программа открывает файл «а» и записывает 50 байтов в файл «а». Однако выполнение этой команды с перенаправлением в файл с недостаточными разрешениями (~ root / log) не приводит к изменению размера файла «a».

$ ./write_file.py >> ~root/log
-bash: /var/root/log: Permission denied
cdal at Mac in ~/experimental/unix_write
$ ls -lt
total 16
-rw-rw-r--  1 cdal  staff  0 Apr 27 08:54 a <-- SHOULD BE 50 BYTES

Можно было бы подумать, что программа запустится, перехватит любой вывод (но также запишет в файл «a»), а затем не сможет записать любой вывод в ~ root / log. Вместо этого программа никогда не запускается.

Почему это так, и как bash выбирает порядок «проверок», которые он выполняет перед выполнением программы? Другие проверки также выполняются?

ps Я пытаюсь определить, действительно ли программа, запущенная под cron, запускалась при перенаправлении в файл «запрещен доступ».


Все в хорошем рабочем состоянии (т. Е. Владельцы и права на ваш файл .py), ваша программа работает нормально. Ваши проблемы происходят от перенаправления. У вас нет разрешения на запись файла в / корневой каталог. И вы перенаправили свой, stdoutчтобы сделать именно это. Таким образом, вы не увидите никакого вывода, даже если ваша программа работала.
— MelBurslan

2
Мел, это неправда, программа никогда не запускалась. Смотрите ответы ниже.
— Чарли Далсасс

Вы: «Запустите write_file.pyпрограмму и отправьте ее вывод ~root/logbash:« Извините, но вы не можете записывать в этот файл! »Оболочка делает именно то, что должна делать. Если она не может сделать то, что вы просили Это немедленно сообщает вам, почему возникает проблема, и дает вам возможность решить, как ее решить. Для всех, кто поддерживает bash, очень плохие вещи могут произойти, если вы запустите эту команду и не сохраните вывод. Если бы это было достаточно важным вы обозначили место , чтобы сохранить его, было бы неправильно ASS | U | ME это было нормально работать без сохранения STDOUT.
— Monty Harder

Ответы:


18

На самом деле это не вопрос упорядочивания чеков, а просто порядок, в котором оболочка все настраивает. Перенаправления устанавливаются до запуска команды; так что в вашем примере оболочка пытается открыть ~root/logдля добавления, прежде чем пытаться сделать что-либо с участием./write_file.py . Поскольку файл журнала не может быть открыт, перенаправление завершается неудачно, и оболочка прекращает обработку командной строки в этой точке.

Один из способов продемонстрировать это - взять неисполняемый файл и попытаться запустить его:

$ touch demo
$ ./demo
zsh: permission denied: ./demo
$ ./demo > ~root/log
zsh: permission denied: /root/log

Это показывает, что оболочка даже не смотрит, ./demoкогда перенаправление не может быть установлено.


Вау, это так просто? Я не понимал, что перенаправления были сделаны в первую очередь. Спасибо за этот ответ и за другие отличные ответы.
— Чарли Далсасс

6
Если бы они не были сделаны первыми, куда бы был записан вывод?
— Чарльз Даффи

И если вывод не может быть записан, как мы можем знать, безопасно ли выполнять команду? Возможно, команда выводит информацию, которая удаляется из хранилища данных, и абсолютно необходимо, чтобы выходные данные были записаны. Хорошо, что bash не даст запустить, пока вы не исправите эти разрешения, а?
— Монти Хардер

11

Со страницы руководства bash, раздел REDIRECTION (выделено мной):

Перед выполнением команды ее ввод и вывод могут быть перенаправлены с использованием специальных обозначений, интерпретируемых оболочкой.

...

Ошибка открытия или создания файла приводит к сбою перенаправления.

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


Спасибо. Я бы хотел, чтобы страница справки немного прояснилась словами «... если вывод не может быть перенаправлен, программа не будет выполнена».
— Чарли Далсасс

Обновлено; это довольно скрытый некоторые параграфы ниже.
— Мерфи

На самом деле, это довольно ясно. «Ошибка открытия или создания файла приводит к сбою перенаправления». Вот оно Еще раз спасибо.
— Чарли Далсасс

3

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

Рассмотрим ваш пример:

./write_file.py >> ~root/log

Что происходит в оболочке:

  1. Мы (оболочка) fork(); дочерний процесс наследует дескрипторы открытого файла от своего родителя (оболочки).
  2. В дочернем процессе мы fopen()(расширение) "~ root / log", и dup2()это до fd 1 (и close()временный fd). Если произошел fopen()сбой, позвоните, exit()чтобы сообщить об ошибке родителю.
  3. Еще у ребенка мы exec()"./write_file.py". Теперь этот процесс больше не выполняет какой-либо из наших кодов (если мы не выполнили его, и в этом случае мы exit()должны сообщить об ошибке родителю).
  4. Родитель будет wait()для ребенка завершать работу и обрабатывать свой код выхода (по $?крайней мере, копируя его ).

Таким образом, перенаправление должно происходить в дочернем элементе между fork()и exec(): это не может происходить раньше, fork()потому что оно не должно изменять стандартный вывод оболочки, и не может происходить после exec()того, как имя файла и исполняемый код оболочки теперь заменены программой Python. , Родитель не имеет доступа к файловым дескрипторам дочернего элемента (и даже если он это сделал, он не может гарантировать перенаправление между exec()и первой записью в стандартный вывод).


0

Мне жаль сообщать вам, что это совсем наоборот. Оболочка должна сначала открыть свой ввод-вывод, а затем передать управление программе.

tee может оказаться полезным в этом случае: ./write_file.py | tee -a ~root/log > /dev/null


Разве скрипт Python просто не умрет на SIGPIPE после того, как произойдет сбой?
— Кевин

Не в соответствии с тестом, который я сделал, но я предлагаю вам попробовать.
— Джули Пеллетье
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.