2013-11-25 4 views
2

Так что у меня этот Баш скрипт:Bash сценарий: `Выход 0` не удается выйти

#!/bin/bash 

PID=`ps -u ...` 
if [ "$PID" = "" ]; then 
    echo $(date) Server off: not backing up 
    exit 
else 
    echo "say Server backup in 10 seconds..." >> fifo 
    sleep 10 

    STARTTIME="$(date +%s)" 

    echo nosave >> fifo 
    echo savenow >> fifo 
    tail -n 3 -f server.log | while read line 
    do 
     if echo $line | grep -q 'save complete'; then 
      echo $(date) Backing up... 
      OF="./backups/backup $(date +%Y-%m-%d\ %H:%M:%S).tar.gz" 
      tar -czhf "$OF" data 

      echo autosave >> fifo 
      echo "$(date) Backup complete, resuming..." 
      echo "done" 
      exit 0 
      echo "done2" 
     fi 

     TIMEDIFF="$(($(date +%s)-STARTTIME))" 
     if ((TIMEDIFF > 70)); then 
      echo "Save took too long, canceling backup." 
      exit 1 
     fi 
    done 
fi 

В основном, сервер принимает входные данные из FIFO и выходов Server.log. Функция fifo используется для отправки команд stop/start на сервер для автосохранения. В конце, как только он получит сообщение от сервера, что сервер завершил сохранение, это каталог данных tar и начинает сбрасываться снова.

На линии exit 0 у меня возникают проблемы. Все выполняется отлично, но я получаю этот результат:

srv:scripts $ ./backup.sh 
Sun Nov 24 22:42:09 EST 2013 Backing up... 
Sun Nov 24 22:42:10 EST 2013 Backup complete, resuming... 
done 

Но он висит там. Обратите внимание, что «сделано» эхом, но «done2» терпит неудачу. Что-то заставляет его висеть на exit 0.

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

Любые мысли? Это весь скрипт, ничего больше не происходит, и я называю его прямым от bash.

+0

«Выход 0 не может выйти»? Вы сами это видите, это выход: P –

ответ

8

Вот меньше, самодостаточный пример, который демонстрирует такое же поведение:

echo foo > file 
tail -f file | while read; do exit; done 

Проблема заключается в том, что с каждой стороны трассы трубопровода в субоболочке, exit выходит только петлю while read, а не весь сценарий ,

Он будет висеть до тех пор, пока tail не найдет новую линию, попытается ее записать и обнаружит, что труба сломана.

Чтобы исправить это, вы можете заменить

tail -n 3 -f server.log | while read line 
    do 
     ... 
    done 

с

while read line 
do 
    ... 
done < <(tail -n 3 -f server.log) 

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

+0

Это была именно эта проблема. Полезно знать в будущем. :) –

1

Но он висит там. Обратите внимание, что «сделано» эхом, но «done2» терпит неудачу.

done2 не будет печататься на всех, так как exit 0 уже закончился ваш сценарий с return code 0.

+0

Я имею в виду, что он печатает «сделано», но _всегда возвращается в командную строку_.«Done2» просто указывает, что он не передает выход и переходит в цикл задержки. –

+0

Вы пишете: 'В принципе, сервер принимает данные от fifo' Я его нигде не вижу. – anubhava

0

Я не знаю деталей подстроек bash внутри циклов, но обычно подходящим способом выхода из цикла является использование команды «break». В некоторых случаях этого недостаточно (вам действительно нужно выйти из программы), но рефакторинг этой программы может быть самым простым (самым безопасным, самым портативным) способом решения этой проблемы. Это также может улучшить читаемость, потому что люди не ожидают, что программы выйдут из середины цикла.

Смежные вопросы