1

sysadmin1138Martinは、ブロック デバイス (パーティション) で動作するrsyncの代替品を報告しています。perlベースですが、双方向差分を保存したいです。

ブロック デバイスの変更を既存の古いバックアップ イメージに適用します。これは、ブロック デバイスが lvm にないために使用しなかったlvmsyncに次いで 2 番目に適しています。

しかし、以前のバックアップ イメージを再生成できるようにするために (たとえば、削除されたファイルを復元するために)、変更を個別に収集することも必要でした。

次のコードは、rsync remplacement の実行時にこれらの変更を収集します。

patch=diff.`date +'%Y%m%d.%H%M%S.%N'`.gz
ssh $username@$backupnas "perl -'MDigest::MD5 md5' -ne   "\
"        'BEGIN{\$/=\1024};print md5(\$_)' $remotepartition        "\
" | gzip -c                                              "\
|gunzip -c|LANG= tee >(wc -c|LANG= sed '1s%^%number of 64 bytes blocs: %' >&2) \
|LANG= perl -'MDigest::MD5 md5' -e 'open DISK,"'"<$partition"'" or die $!; '\
'         while( read DISK,$read,1024)                                     '\
'         {                                                                '\
'           read STDIN,$md,16;                                             '\
'           if($md eq md5($read)) {print "s"} else {print "c" . $read }    '\
'         }                                                                '\
| gzip -c                                                                       \
|ssh $username@$backupnas "touch $remotepartition;LANG= tee -a $patch|gunzip -c"\
"     |perl -e 'open REVP,\"| gzip -c > rev.$patch\";                          "\
"         open PREVIOUS,\"<$remotepartition\";                                 "\
'         $rev = "PREVIOUS met EOF if length<1024."; $rev=$rev.$rev;           '\
'         $rev=$rev.$rev.$rev.$rev; $rev=$rev.$rev.$rev.$rev;                  '\
'         while(read STDIN,$read,1)                                            '\
'         {                                                                    '\
'           if ($read eq "s")                                                  '\
'           {                                                                  '\
'             if (length($rev) eq 1024) { print REVP "s" } ;                   '\
'             $s++                                                             '\
'           } else {                                                           '\
'             if ($s) { seek STDOUT,$s*1024,1; seek PREVIOUS,$s*1024,1; $s=0}; '\
'             if (read PREVIOUS,$rev,1024) { print REVP "c".$rev };            '\
'             read STDIN,$buf,1024;                                            '\
'             print $buf                                                       '\
'           }                                                                  '\
"         }' 1<> $remotepartition                                              "

$rev長さ 1024 のスカラー文字列に初期化されます (これを改善する方法がわかりません)。

フォーマットなしで more を使用すると、次のようになりor dieます。

patch=essai_delta.`date +'%Y%m%d.%H%M%S.%N'`.gz
ssh username@backupnas "perl -'MDigest::MD5 md5' -ne 'BEGIN{\$/=\1024};print md5(\$_)' essai_backup | gzip -c" | \
gunzip -c | LANG= tee >(wc -c|LANG= sed '1s%^%bin/backup_essai: number of 64 bytes blocs treated : %' >&2) | \
LANG= perl -'MDigest::MD5 md5' -e 'open DISK,"</data/data/com.spartacusrex.spartacuside/files/essai" or die $!; while( read DISK,$read,1024) { read STDIN,$md,16; if($md eq md5($read)) {print "s"} else {print "c" . $read } }' /data/data/com.spartacusrex.spartacuside/files/essai | \
gzip -c | \
ssh username@backupnas "LANG= tee -a $patch | gunzip -c | perl -e 'open REVP,\"| gzip -c > rev.$patch\" or die \$!; open READ,\"<essai_backup\" or die \$!; \$rev = \"if length<1024, EOF met in READ.\"; \$rev=\$rev.\$rev.\$rev.\$rev; \$rev=\$rev.\$rev.\$rev.\$rev; \$rev=\$rev.\$rev; while(read STDIN,\$read,1) { if (\$read eq \"s\") {if (length(\$rev) eq 1024) { print REVP \"s\" or die \$! } ; \$s++} else { if (\$s) { seek STDOUT,\$s*1024,1 or die \$!; seek READ,\$s*1024,1 or die \$!; \$s=0}; if (read READ,\$rev,1024) { print REVP \"c\".\$rev or die \$! } else { print STDERR \$!}; read STDIN,\$buf,1024 or die \$!; print \$buf  or die \$!} }' 1<> essai_backup"

前方または後方差分を適用するには、次を使用できます。

ssh username@backup_nas "LANG= cat diff_delta.20141202.110302.0935 | gunzip -c | perl -ne 'BEGIN{\$/=\1} if (\$_ eq\"s\") {\$s++} else {if (\$s) { seek STDOUT,\$s*1024,1; \$s=0}; read STDIN,\$buf,1024; print \$buf}' 1<> image.file"

それで、この投稿の最初のバージョンに答えることに成功しました。これは、いくつかの変更を加えた 200k の例でテストされました。

このコードについて具体的な質問があります。

なぜ元の例が使用されたのread ARGVですか?それは悪い習慣ですか?

私はたくさん入れましたor die $!が、それは賢明ですか、それとも読みやすさを損なうだけですか?

PREVIOUSSTDOUT同じファイルが 2 回開かれている場合 (回避するため) seek STDOUT,-1024,1、それは良い習慣と見なされますか?

[ programmers.soから手動で移行された質問]

4

1 に答える 1

2

使用された元の例がARGVを読んだのはなぜですか?それは悪い習慣ですか?

これは宗教的な質問です。このような 1 行の SSH ハックの場合、あなたとそれらを維持する可能性が高い人々が perl のイディオムに非常に優れていれば、多かれ少なかれ問題ありません。しかし一般的な知恵は、新しい perl コードはuse strict;より直観的に読める慣習を採用すべきであるということです。あなたが裸について尋ねなければならなかったという事実とARGV、あいまいな perlmonk の記事を参照する必要があったという事実が、まさにその理由です。適切に作成された読み取り可能なスクリプトをターゲット マシンの標準的な場所に配布し、単純なssh コマンドを使用してリモートで実行する機会を探しています。一方、上記の方法は、雇用の安定に最適です。

私は多くを入れたか、$! を使い果たしました。それは賢明ですか、それとも可読性を損なうだけですか?

不明瞭なデフォルトのエラー トレースを取得するよりも、スクリプトが停止した理由を知ることは常に便利です。読みやすさの問題は、かなり大きなスクリプトを ssh コマンドに入れるというこの壊れた手法を使用していることだけです。上で提案したように、より健全な環境を設定すれば、追加or die $!によって読みやすさが損なわれることはまったくありません。エラーが発生する可能性がある場所を示すことで、それを強化します。

PREVIOUS と STDOUT は 2 回開かれた同じファイルです (シーク STDOUT、-1024,1 を避けるため)。

OS で許可されている場合、同じスレッドで同じファイルの 2 つの記述子を開くことは悪い習慣ではありません。少しわかりにくいので、コメントが必要です。これは、インライン スクリプトを使用しない場合にできるもう 1 つのことです。

本当に奇妙なのは、$rev1024 文字を取得するために連結を繰り返すことによって、バッファが文字列として構築される方法です。これは不要です。と言うだけ$rev = '';で、文字列の長さは によって入力サイズに自動的に拡張されreadます。本当に事前に割り当てたい場合は、 と言って$rev = '-' x 1024;ください。

添加

の便利な機能について知りましたbash。フォーマット指定子を使用するとprintf、任意の文字列にエスケープ%qが追加されます。bashこれにより、エスケープフリーbashおよび/またはperlコードを記述してから言うことができます

ssh $username@$backupnas "$(printf "%q" $(cat script.bash))"
于 2014-04-09T01:02:09.133 に答える