Вы можете сбросить ловушку до значения по умолчанию, задав команду ловушки -
в качестве аргумента действия. Если вы сделаете это в подоболочке , это не повлияет на ловушку в родительской оболочке. В вашем скрипте вы можете сделать это для каждой команды, которую вам нужно прерывать с помощью Ctrl -C:
#!/bin/bash
# make the shell (and its children) ignore SIGINT
trap '' INT
.
.
.
# but this child won't ignore SIGINT
(trap - INT; my_program)
# the rest of the script is still ignoring SIGINT
.
.
.
Вы подтвердили, что используете загрузочный образ, поэтому исходный диск объемом 1 ТБ в настоящее время не используется. Это действительно хорошая новость.
Теперь, чтобы скопировать диск через ненадежный носитель, вам нужен либо транспортный уровень, который может автоматически -устанавливать себя (, например, OpenVPN через UDP ), либо средство для отправки перезапускаемых «фрагментов» данных.
Предположим, что все управляется с клиента и что у вас ssh
доступ опосредован сертификатами/ключами, поэтому пароли не требуются.
Я предлагаю вам использовать блоки по 1 ГБ, что означает, что вам потребуется около 1000 ssh
подключений для передачи всего диска. Возможно, вы захотите настроить размер блока и количество в верхней части скрипта. В разделе «Действительные данные» вы можете выбрать запись bzip2
сжатого фрагмента или обычного несжатого фрагмента.(bzip2
может работать с несколькими сжатыми фрагментами, так что это не проблема.)
#!/bin/bash
#
dev=/dev/sda1 # Device to read
img=image.dat # Target image filename
bs=32M # dd blocksize per read
count=32 # Number of blocks per ssh chunk
for (( chunk=0; ; ))
do
# Grab chunk from server
#
ssh -zn root@remoteServer "
dev=$dev chunk=$chunk bs=$bs count=$count "'
echo "chunk $chunk from device $dev"
{
dd bs=$bs skip=$((chunk*count)) count=$count if=$dev 2>/tmp/dd.$$
echo $? >/tmp/ss.$$
dd bs=$bs iflag=fullblock count=$count if=/dev/zero 2>/dev/null
} | dd bs=$bs iflag=fullblock count=$count 2>/dev/null
echo "========"
echo "status $(cat /tmp/ss.$$)"
cat /tmp/dd.$$
rm -f /tmp/dd.$$ /tmp/ss.$$
' |
{
# Extract data from chunk
#
IFS= read -r info
echo "Received: $info"
dd bs=$bs iflag=fullblock count=$count of=/var/tmp/data.$$
cat >/var/tmp/meta.$$
}
# Append extracted data
#
meta=$(cat /var/tmp/meta.$$)
echo "Meta:"
echo "$meta" | sed 's/^/| /'
if [[ "$meta" =~ ([[:digit:]]+)\+[[:digit:]]+' records in' ]]
then
# Valid data
#
# bzip2 </var/tmp/data.$$ >> "$img.bz2"
dd bs=$bs count=$count seek=$((chunk*count)) conv=notrunc if=/var/tmp/data.$$ of="$img"
# Is this all
#
if [[ "${BASH_REMATCH[1]}" -lt $count ]]
then
# We are done
#
break
fi
# Next round the loop
#
((chunk++))
else
echo "Invalid data received for chunk $chunk; retrying"
fi
done
# Tidy up
#
rm -f /var/tmp/data.$$ /var/tmp/meta.$$
exit 0
Результирующий образ будет не меньше размера исходного диска; дополнительных нулевых байтов будет достаточно для округления до следующего полного размера фрагмента. Вы можете использовать truncate
, чтобы уменьшить размер результирующего несжатого изображения, если это важно.
Боюсь, чтобы отправить недостающий бит, вам все равно придется повторно сжимать с самого начала, даже если вы передаете только недостающие биты, поскольку поток сжатия, такой как поток bzip2, зависит от того, что вы видели раньше.
Если $s
содержит размер того, что уже было передано, вы должны сделать
dd if=/dev/md3 status=progress bs=500k | bzip2 --best | {
head -c "$s" > /dev/null
ssh host 'cat >> /mnt/client/image.bz2'
}
(предполагается head
реализация, такая как GNU head
, которая не читает больше, чем требуется здесь ).
Или наоборот:
ssh other-host "
dd if=/dev/md3 status=progress bs=500k | bzip2 --best |
tail -c +$(($s + 1))" >> /mnt/client/image.bz2
Это предполагает, что /dev/md3
не был изменен (и даже не смонтирован, что может обновить некоторое поле «время последнего монтирования», например )с последнего раза.
Также не рекомендуется использовать сетевую файловую систему для передачи больших файлов.