Я использую 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
команды увидят пустой ввод и немедленно закончат обработку.