Трубопровод Bash: разделить ввод после 1-й строки, выполнить разные команды в 1-й строке и остальные - PullRequest
2 голосов
/ 10 февраля 2012

У меня есть скрипт резервного копирования, который копирует файл через ssh и создает файл хэша во время передачи. Дополнительно pv используется для отображения индикатора выполнения:

ssh $host "cat '$src_dir/$filename'" \
    | pv --bytes --eta --progress --rate --timer --wait  $opts \
    | tee "$filename" \
    | sha1sum > "$filename.sha1"

Чтобы правильно отобразить индикатор выполнения, мне нужно передать размер файла в pv. Сейчас я делаю это, указав размер последнего файла резервной копии.

Важно, чтобы все было сделано с вызовом 1 ssh, потому что я не хочу авторизовать несколько раз для одной резервной копии. Ключи SSH используются, но защищены парольной фразой.

Моя идея - вызвать ssh $host "stat -c%s '$src_dir/$filename'; cat '$src_dir/$filename'" и разбить вывод после 1-й строки. Я мог бы прочитать размер файла и затем вызвать pv на остальной части ввода.

Сценарий резервного копирования работает нормально. Это просто упражнение для удовольствия. Любые идеи приветствуются, но я не буду полностью переписывать весь сценарий. Особенно я не буду переключаться на scp, потому что тогда я не могу выполнить хэширование во время передачи и не хочу доверять локальному хранилищу для этого (конечно, я делаю, но тогда почему мы все равно делаем хеширование?) .

Обновление: Я закончил этим:

ssh $host "cd '$src_dir' && stat -c%s '$filename' && sha1sum '$filename' && cat '$filename'" | {
        read size;
        head -n 1 > "$filename.sha1";
        pv --bytes --eta --progress --rate --size $size --timer --wait > "$filename"
    }

Он отлично работает и имеет преимущество в том, что хэш вычисляется на удаленном сайте. Так что не только перед записью на диск, но и перед передачей по сети.

1 Ответ

2 голосов
/ 10 февраля 2012

В этом примере я использую stat в OSX, который использует z для строки формата для размера:

$ { stat -f %z input; cat input; } | { read s; echo $s; }

Замените первый список команд вашим вызовом ssh и замените echo вашим списком pvи тебе пора идти.Другими словами, ваша последняя команда должна быть:

$ ssh $host "stat -c%s '$src_dir/$filename'; cat '$src_dir/$filename'" | {
    read size;
    pv --bytes --eta --progress --rate --timer --wait --size $size |
    tee "$filename" |
    sha1sum; } > "$filename.sha1"

Несколько замечаний: у меня нет доступа к pv и я не проверял вышеуказанное.Я заменил ваши продолжения строки символами трубы, потому что я думаю, что это выглядит лучше.

Другая идея: с правой стороны трубы вы можете сделать:

{ pv --bytes ... --size $( sed 1q ) |
...

Это определенно зависитна sed не читается после первой новой строки, и я не знаю, гарантируется ли это каким-либо стандартом, но он работает с ... о боже, мой sed не поддерживает --version, -? или -h, и яне достаточно хорошо знаю систему управления пакетами OS X, чтобы сказать вам, что я использую.Работает с какой-то версией BSD sed ...

...