Итоговые выводы:
Чтобы запустить команду асинхронно, нужно:
1. Перенаправить основной поток вывода из консоли (в /dev/null или файл)
2. Использовать после команды символ &
nohup и другие дополнительные команды не нужны
В моем случае это всё не сработало. Мне требуется получить код выхода rsync. По какой-то причине этот код не попадает ни stdout, ни в stderr. В итоге мне пришлось использовать конструкцию:
rsync params && echo $? >> /log.txt 2>&1 &
Именно эта конструкция по какой-то причине не работает асинхронно.
Чтобы код заработал асинхронно, потребовалось создать прослойку в виде bash-скрипта:
#!/bin/bash
rsync -avz -e "ssh -p $2 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" $3@$1:$4 $5 >> $6 2>&1
echo $? >> $6
# rsync_download.sh sshHost sshPort sshLogin target destinity logPath
И запускать её асинхронно:
$command = $shDir . "rsync_download.sh $sshHost $sshPort $sshLogin $directory $snapshotPath $logPath > /dev/null 2>&1 &";
exec($command);
Это ужасное и громоздкое решение.
Если кто-то сможет объяснить причину проблемы и подсказать аккуратное решение без bash-скрипта, буду очень благодарен.
Тестовый пример, который подтверждает проблему с echo:
exec('grep -r "user" /folder/ && echo $? >> /home/user1/web/backuper.ru/web/log.txt 2>&1 &');