Во-первых, можно упростить команды SSH путем добавления псевдонима к Вашему ~/.ssh/config
файл.
Host somehost
HostName some.host
User vivek
IdentityFile /where/is/my/id_dsa
На основной сути: необходимо выполнить два шага, сначала определить, который файл скопировать (который должен быть сделан на удаленной стороне), затем скопируйте или обновите тот файл. Было бы легче, если бы Вы не должны были волноваться, о котором файлы являются удаленными и которые локальны. Поэтому смонтируйте удаленную файловую систему с sshfs.
mkdir somehost
sshfs somehost:/ somehost
Можно теперь действовать полностью на локальные файлы. Необходимо, вероятно, передать --no-whole-file
опция к rsync
, потому что иначе это предполагает, что локальная файловая система быстра и будет всегда копировать целый файл, а не применять свой возрастающий алгоритм дельты.
rsync -avz --progress --no-whole-file $(find somehost/remote/source/dir -type f -name '*.sql' | sort -nr | head -1) .
Теперь, вместо того, чтобы звонить find
, используйте zsh в качестве своей оболочки. Как большинство find
вызовы, Ваш может быть заменен несколькими спецификаторами шарика: .
для -type f
, On
для числового вида, и [1]
сохранять только первое соответствие.
rsync -avz --progress --no-whole-file somehost/remote/source/dir/**/*.sql(.on[1]) .
Просто вставьте команду в цикл while
. Здесь есть ряд нюансов, но в основном (в bash
или любой оболочке POSIX):
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Другая основная проблема с этим (кроме IFS
ниже) - это когда вы пытаетесь использовать переменные внутри цикла после его завершения. Это происходит потому, что цикл на самом деле выполняется в под-оболочке (просто другой процесс оболочки), из которой вы не можете получить доступ к переменным (также она завершается, когда завершается цикл, и в этот момент переменные полностью исчезают. Чтобы обойти это, вы можете сделать:
longcommand | {
while IFS= read -r line
do
whatever "$line"
lastline="$line"
done
# This won't work without the braces.
echo "The last line was: $lastline"
}
Пример Хауке о настройке lastpipe
в bash
является другим решением.
Чтобы убедиться, что вы обрабатываете вывод команды "по мере ее выполнения", вы можете использовать stdbuf
для установки stdout
процесса в режим линейной буферизации.
stdbuf -oL longcommand |
while IFS= read -r line
do
whatever "$line"
done
Это настроит процесс на запись одной строки за раз в трубу вместо внутренней буферизации вывода в блоки. Имейте в виду, что программа может сама изменить эту настройку. Аналогичного эффекта можно добиться с помощью unbuffer
(часть expect
) или script
.
stdbuf
доступен в системах GNU и FreeBSD, он влияет только на stdio
буферизацию и работает только для не-setuid, не-setgid приложений, которые динамически связаны (поскольку использует трюк LD_PRELOAD).
#! /bin/bash
set +m # disable job control in order to allow lastpipe
shopt -s lastpipe
longcommand |
while IFS= read -r line; do lines[i]="$line"; ((i++)); done
echo "${lines[1]}" # second line