Bash Script зависает при запуске в программе go - PullRequest
1 голос
/ 30 мая 2019

У меня есть сценарий bash postinstall.sh, который обычно запускается при запуске из терминала

./postinstall.sh

сценарий запускает несколько команд, создавая каталоги, файлы chown, chmod и каталоги,

в конце скрипта равно

echo "Done"
exit 0

Когда я запускаю это как exec.Cmd в go и вызываю функцию cmd.Wait (), она никогда не возвращается.

Поэтому я изменил свой код, чтобы использовать пакет из https://github.com/go-cmd/cmd, так как я хотел иметь возможность регистрировать выходные данные скриптов, которые я запускаю в режиме реального времени, но также определять, когда они завершены.Таким образом, после некоторой работы я теперь могу записать stdOut Cmd в мою запись в logLevel STATUS и stdErr Cmd в мою logLevel ERROR.Я также могу установить тайм-аут для команды и записывать ее ход в реальном времени.

Этот новый процесс работает, как и ожидалось, для некоторых простых случаев, но когда я запускаю большой скрипт postinstall.sh, он запускается до самого конца, а затем зависает и, в конце концов, останавливается.Процесс занимает несколько секунд при запуске вручную из командной строки, я установил таймаут на 30 секунд.запись показывает

STATUS- Done

, которая является строкой прямо перед

exit 0

Документы для пакета go-cmd показывают неблокирующий способ сообщить, что процесс завершен,который я проверяю (и работает в моих тестовых примерах), я также проверяю флаг cmd.Status (). Finished (bool), и ни один из них не сообщает о завершении процесса.Это тот же самый результат, который я видел, просто используя функцию cmd.Wait () из встроенного exec.Cmd, только теперь я вижу, что скрипт делает это до самого конца, но по какой-то причине либо нетвозвращаясь, или программа go не может сказать, что вернулась.

Часть того, что делает скрипт, запускает или перезапускает сервисы в /etc/init.d, если один из них запускает процесс в фоновом режиме, так как родительский процесс - это скрипт постинсталляции, который может вызвать процессне полностью завершить в глазах программы go?

Или какие-либо другие типы команд, которые могут вызвать такой тип поведения?

Возможно, мне просто нужно начать удалять части скрипта и посмотреть, смогу ли я завершить его, чтобы сузить причину, по которой это действует иначе, чем мой тестовый скрипт, но его около 100 строк и процессполучить сценарий в устройство - это многошаговый процесс.

testscript был чем-то вроде

#!/bin/bash

echo "stdOut"
sleep 1
>2& echo "stdErr"
sleep 2
echo "Finsihed"
sleep 1

, и это сработало как ожидалось (тайм-аут, когда лимит был 1 секунда, показалзавершено, когда тайм-аут был установлен на 4 секунды)

Следует также отметить, что процесс работает на других сценариях.это часть процесса обновления, который выполняет preinstall.sh, затем использует этот же процесс для вызова tar -xvf для файла, содержащего обновление, а затем переходит к этому сценарию postinstall.Таким образом, большую часть времени мой процесс успешно обнаруживает, что процесс завершился, есть только что-то в postinstall, которое решает проблему, но я не могу думать о том, что заставило бы его зависать на ходу, но выходил нормально при запуске из терминала.

1 Ответ

0 голосов
/ 30 мая 2019

Вот из документов для Cmd.wait с акцентом:

func (c *Cmd) Wait() error

Ожидание ожидает команды для выхода и ожидает любого копирования в stdin иликопирование из stdout или stderr для завершения.

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

Вот пример:

#!/bin/bash
sleep 3600 &
echo "Exit"

sleep наследует stdin / out / err и держит их открытыми в течение часа.Он немедленно выйдет из терминала, потому что Bash не заботится о том, что терминал открыт:

$ ./testscript; echo "Returned"
Exit
Returned
$

Однако, если вы отправите трубку на cat, он будет ждать, пока все потенциальные данные не будут отправлены.окончания (в случае, если sleep решит написать что-то позже), и bash по очереди ожидает cat:

$ ./testscript | cat; echo "Returned"
Exit
(Hangs for an hour)

Это можно исправить, убедившись, что все разветвленные процессы не будут записывать втруба путем перенаправления куда-то еще:

#!/bin/bash
sleep 3600 < /dev/null > /dev/null 2>&1 &
echo "Exit"

Так как sleep больше не удерживает трубу открытой, она немедленно возвращается, как в оболочке, так и с Cmd.Wait():

$ ./testscript | cat; echo "Returned"
Exit
Returned
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...