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 завершается неудачно, поэтому я заменил первую строку следующим образом:

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, что сбивает с толку команду read. Комментирование ssh-команды заставляет цикл работать как надо.

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

72 голоса | спросил Robby75 22 FebruaryEurope/MoscowbWed, 22 Feb 2012 14:28:16 +0400000000pmWed, 22 Feb 2012 14:28:16 +040012 2012, 14:28:16

3 ответа


0

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

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

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

ответил choroba 22 FebruaryEurope/MoscowbWed, 22 Feb 2012 14:34:55 +0400000000pmWed, 22 Feb 2012 14:34:55 +040012 2012, 14:34:55
0

Другой подход заключается в создании цикла для 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, а не FD 0 по умолчанию (стандартный).

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

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

ответил Charles Duffy 3 MarpmTue, 03 Mar 2015 20:09:49 +03002015-03-03T20:09:49+03:0008 2015, 20:09:49
0

Кроме ответа Чоробы , не используйте for цикл для чтения имен файлов:

find devel/ -newer $UPLOAD_FILE | 
while read -r i
do ...
ответил glenn jackman 22 FebruaryEurope/MoscowbWed, 22 Feb 2012 19:24:56 +0400000000pmWed, 22 Feb 2012 19:24:56 +040012 2012, 19:24:56

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132