Назад | Перейти на главную страницу

Фоновое задание завершается при запуске из сценария, но отлично работает при запуске из командной строки bash

Я использую MacOS 10.9.4. Я хочу перевести sftp в фоновый режим, чтобы позже автоматически передавать ему некоторые файлы через именованный канал, как было предложено Вот. Он отлично работает, когда я ввожу команды вручную из командной строки bash (используя cat в качестве слушателя для простоты):

    $ mkfifo test
    $ cat > test &
    [1] 60765
    $ cat test | cat &
    [2] 60781 60782
    [1]  + 60765 suspended (tty input)  cat > test
    $ echo works! > test
    works!
    $ ps -ax | grep 60765
    60765 ttys023    0:00.00 cat
    60900 ttys023    0:00.00 grep 60765

Однако, когда я помещаю это в сценарий bash, он перестает работать:

    $ cat test.sh
    mkfifo test1
    cat > test1 &
    echo $!
    cat test1 | cat &
    $ bash test.sh
    60847
    $ echo fails > test1
    ^C%
    $ ps -ax | grep 60847
    60882 ttys023    0:00.00 grep 60847

Проблема здесь, как я понимаю, в том, что cat > test1 & line отлично работает при запуске из приглашения, но каким-то образом завершается при запуске из скрипта, поэтому мое задание слушателя получает EOF и тоже завершается.

Что мне здесь не хватает и как заставить это работать из скрипта?

Изменить: настоящая проблема, с которой я столкнулся, заключается в следующем. Для разработки мне нужно развернуть код на удаленном сервере. Для этого я использовал rsync, а чтобы немного автоматизировать это, я использовал fswatch для прослушивания изменений файлов в папке и запуска rsync, когда это изменение произойдет.

    $ fswatch -0 . | while read -d "" event;
      do
        rsync ./ {remote folder}
      done

Он работал нормально, пока я не попытался использовать его при медленном соединении с большой задержкой. Rsync каждый раз открывает новое соединение ssh и находит различия в файлах, что требует времени при медленном соединении. Я пытаюсь обойти это, открывая постоянное соединение с sftp и нажимая на него только измененный файл, имя которого я получаю от fswatch. Чтобы это работало, мне нужен способ запустить процесс sftp и отправить ему команды позже, когда произойдет событие fswatch. я обнаружил этот вопрос, но запись в / proc / {pid} / fd / 0 не должна была работать на Mac, поэтому я пытался использовать ответ с именованными каналами. Я могу бегать cat > test1 & вручную перед запуском скрипта fswatch, так что это действительно сработает. Но мне нужно надежное решение, чтобы можно было передать этот сценарий моим коллегам.

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

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

cat > test & будет пытаться читать с терминала немедленно и будет приостановлен. Однако вас уведомляет об этом только bash непосредственно перед отображением следующего приглашения, поэтому вам нужно ввести другую команду, прежде чем вы получите уведомление.

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

Во втором примере весь сценарий выполняется в одной группе процессов. Итак, на данный момент у вас есть три разных cat команды в группе процессов, и одна из них заблокирована при чтении с терминала. Затем вы вернетесь к исходному bash shell, так что эта группа потоков должна быть приостановлена.

Более того, с точки зрения вашего первоначального bash shell, эта группа потоков уже завершена, потому что она увидела вторую bash команда, которую вы ввели завершить. Начальный bash Оболочка не знает, что дочерний процесс породил внуков, и что одному из них было заблокировано чтение с терминала.

Когда группа процессов вашего скрипта больше не находится под контролем начального bash оболочка, первая cat команда получит на входе EOF. На данный момент все cat команды увидят пустой ввод и немедленно закончат обработку.