ssh вырывается из цикла while в bash

Я использую этот bash-код для загрузки файлов на удаленный сервер, для обычных файлов это отлично работает:

for i in `find devel/ -newer $UPLOAD_FILE` do echo "Upload:" $i if [ -d $i ] then echo "Creating directory" $i ssh [email protected]$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" continue fi if scp -Cp $i [email protected]$SERVER:$REMOTE_PATH/$i then echo "$i OK" else echo "$i NOK" rm ${UPLOAD_FILE}_tmp fi done 

Единственная проблема заключается в том, что для файлов с пробелом в имени, for-loop терпит неудачу, поэтому я заменил первую строку следующим образом:

 find devel/ -newer $UPLOAD_FILE | while read i do echo "Upload:" $i if [ -d $i ] then echo "Creating directory" $i ssh [email protected]$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" continue fi if scp -Cp $i [email protected]$SERVER:$REMOTE_PATH/$i then echo "$i OK" else echo "$i NOK" rm ${UPLOAD_FILE}_tmp fi done 

По какой-то странной причине команда ssh вырывается из цикла while, поэтому первый недостающий каталог создается отлично, но все последующие отсутствующие файлы / каталоги игнорируются.

Я предполагаю, что это связано с тем, что ssh пишет что-то в stdout, что смущает команду «читать». Комментируя команду ssh, цикл работает так, как должен.

Кто-нибудь знает, почему это происходит и как можно предотвратить ssh от нарушения цикла while?

Проблема в том, что ssh читает со стандартного ввода, поэтому он ест все оставшиеся строки. Вы можете просто подключить его стандартный вход в никуда:

 ssh [email protected]$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" < /dev/null 

Вы также можете использовать ssh -n вместо перенаправления.

Другим подходом является петля над FD, отличная от stdin:

 while IFS= read -u 3 -r -d '' filename; do if [[ -d $filename ]]; then printf -v cmd_str 'cd %q; mkdir -p %q' "$REMOTE_PATH" "$filename" ssh "[email protected]$SERVER" "$cmd_str" else printf -v remote_path_str '%[email protected]%q:%q/%q' "$USER" "$SERVER" "$REMOTE_PATH" "$filename" scp -Cp "$filename" "$remote_path_str" fi done 3< <(find devel/ -newer "$UPLOAD_FILE" -print0) 

Операторы -u 3 и 3< являются критическими здесь, используя FD 3, а не FD0 по умолчанию (stdin).

Приведенный здесь подход - использование -print0 , очищенное значение IFS и т. П. - также менее ошибочно, чем исходный код и существующий ответ, который не может правильно обрабатывать интересные имена файлов. (Ответ Гленна Джекмана близок, но даже это не может иметь дело с именами файлов с новыми символами или именами файлов с завершающим пробелом).

Использование printf %q имеет решающее значение для создания команд, которые нельзя использовать для атаки на удаленную машину. Подумайте, что произойдет с файлом с именем devel/$(rm -rf /)/hello с кодом, который не имел этой паранойи.

В дополнение к ответу choroba , не используйте цикл for для чтения имен файлов:

 find devel/ -newer $UPLOAD_FILE | while read -ri do ... 
  • Wake-on-LAN через Интернет практически невозможно
  • PuTTY не отправляет Esc
  • Solaris: ssh -tt без вывода
  • Пересылка порта ssh с удаленного места на компьютеры в сети сервера
  • Как git клонировать частные репозитории в Vagrant VM, используя ключи SSH хоста?
  • Как ssh два компьютера за NAT и брандмауэром, без третьего компьютера
  • Как редактировать текстовые файлы в командной строке Windows?
  • Ошибка согласования алгоритма SSH в Дженкинсе
  • SSH не будет работать в новой версии OS X 10.8.4
  • Если я опечатаю свое имя пользователя при ssh-ing, есть ли способ вернуться и изменить его?
  • Как установить переменные среды для удаленного процесса rsync?
  • Давайте будем гением компьютера.