Усложненный?
Переменные в стороне на мгновение. Это ваш основной код:
split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> /root/myfilecopy.gz"' /dev/myblockdev
Прежде всего: cat
здесь бесполезна.
Далее я думаю, что добавление результатов последовательных gzip
-s в один и тот же файл (>>
) отменяет работу split
. Теоретически, в конце вы получите gzip /dev/myblockdev
, как если бы вы это сделали:
ssh root@$remote_ip 'gzip > /root/myfilecopy.gz' < /dev/myblockdev
На практике я бы подумал о состоянии гонки. Я ожидаю, что split
будет запускать ssh
-s последовательно на локальной стороне; но я не удивлюсь, если при некоторых обстоятельствах различные буферы или лаги на удаленной стороне станут причиной записи следующего gzip
до того, как закончится предыдущий. Это повредит myfilecopy.gz
. Открытие файла только один раз предотвращает это.
Если бы вы использовали $FILE
(смотрите man 1 split
) и писали в несколько файлов, я бы увидел смысл в использовании split
. Обратите внимание, что это не приведет к состоянию гонки, поскольку каждый из этих файлов будет открыт только один раз.
Вывод: split
, вероятно, бесполезен, cat
наверняка бесполезна; неосторожное добавление может повредить полученный файл.
Вопрос, о котором вы спрашивали
Хорошо, давайте предположим, что у вас есть причины использовать split
и >>
таким образом (хотя ваш cat
все еще бесполезен).
Ваша текущая оболочка знает значение $remote_file
, но split
и ее фильтры являются дочерними процессами, и они не наследуют переменную, если вы не export
ее заранее. Несуществующая переменная расширяется до нуля, поэтому соответствующий фрагмент выглядит как gzip >> (newline)
, отсюда и ошибка.
То же самое относится и к $remote_ip
. Я предполагаю, что в вашем коде вы используете не $remote_ip
а фактический IP-адрес 192.168.0.105
. Отныне я использую remote_ip
в качестве заполнителя (то есть не переменной оболочки) для фактического IP-адреса.
Для export
:
remote_file="/root/myfilecopy.gz"
export remote_file
# now your split command should utilize the variable as you expected
В качестве альтернативы вы можете сделать вашу текущую оболочку развернутой $remote_file
в момент запуска split
. Первоначально строка $remote_file
осталась без изменений из-за одинарных кавычек. Следующий синтаксис изменяет тип кавычек только для этой одной переменной:
split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> '"$remote_file"'"' /dev/myblockdev
# close a single quote ^ ^ and open again
# variable inside double quotes ^^^^^^^^^^^^^^
Таким образом, split
никогда не получает литерал $remote_file
, он получает его значение.
Еще одна проблема
Если бы вы имели remote_file="/root/myfile copy.gz"
, пространство в пути разделило бы его на два аргумента на удаленной стороне. По этой причине более надежный подход требует дополнительного цитирования. Это вышеупомянутый подход "без экспорта" с дополнительными кавычками (экранируется с \
):
split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> \"'"$remote_file"'\""' /dev/myblockdev
Давайте раздеть это шаг за шагом. Среди других аргументов, split
будет выглядеть следующим образом:
--filter=ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""
Это запустит этот фильтр в bash
:
ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""
Тогда ssh
увидит это как один из аргументов:
gzip >> "/root/myfile copy.gz"
Таким образом, на удаленной стороне перенаправление будет "/root/myfile copy.gz"
. Без этих добавленных цитат вы бы получили:
gzip >> /root/myfile copy.gz
что эквивалентно
gzip copy.gz >> /root/myfile
Дополнительные примечания
- Если локальный процессор достаточно быстрый, рассмотрите
gzip
перед ssh
. Таким образом вы проталкиваете меньше данных через сетевую ссылку (и); особенно если вы подготовили свое блочное устройство к хорошему сжатию .
- Если вы намеревались запустить несколько процессов
gzip
чтобы получить преимущество от нескольких ядер ЦП, то обратите внимание, что они все равно будут работать последовательно; если нет - состояние гонки - вы этого не хотите. Познакомьтесь с pigz
.