Linux の zipコマンドはよく使われるコマンドであり、さまざまなオプションがあります。その中でファイルのバックアップに便利そうなオプションを今回は紹介します。


基本的な使い方

まず zip のおさらいです。基本的な使い方は簡単です。引数に作成する zipファイル名と圧縮するファイル名を渡せばOKです。 たとえば下記のようなファイルとディレクトリがあったとします。これを全部 zip にかためてバックアップを取ることを考えます。

1
2
3
4
5
6
7
8
$ tree
.
├── a.txt
├── b.txt
├── c.txt
└── foo
    ├── fuga.txt
    └── hoge.txt

ここでカレントディレクトリ以下全部を圧縮してみます。下記のように-r(--recurse-paths)の再帰オプションとワイルドカードを組み合わせればできます。 また、unzip -lzipの中のファイル一覧を表示するコマンドです。期待通り全部格納されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ zip -r backup.zip ./*
  adding: a.txt (stored 0%)
  adding: b.txt (stored 0%)
  adding: c.txt (stored 0%)
  adding: foo/ (stored 0%)
  adding: foo/hoge.txt (stored 0%)
  adding: foo/fuga.txt (stored 0%)
$ unzip -l
Archive:  backup.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2022-02-24 23:24   a.txt
        0  2022-02-24 23:24   b.txt
        0  2022-02-24 23:24   c.txt
        0  2022-02-24 23:25   foo/
        0  2022-02-24 23:24   foo/hoge.txt
        0  2022-02-24 23:25   foo/fuga.txt
---------                     -------
        0                     6 files

変更されたファイルだけ更新する

つぎにファイルが変更されたときのことを考えます。 ファイルが変更されたらbackup.zip も作り直す必要がありますね。 いったん backup.zip を消して再度zipしてもいいのですが、 もしファイルが多かったり大きかったりするとその方法では効率が悪いです。

そこで登場するのが -u (--update)オプションです。-uをつけると、変更されたファイルだけを更新できます。 下記の例では a.txtを変更し、 -u オプションをつけることで zip 内の a.txtだけを更新しています。 このとき変更されていない他のファイルは更新されません。これで不要な処理を省けます。 大量のファイルのバックアップを取るときはこのオプションが便利です。

1
2
3
4
$ zip -r -u backup.zip ./* # backup.zip はなにも更新されない
$ touch a.txt
$ zip -r -u backup.zip ./*  # a.txt が更新されたので backup.zip の a.txt も更新される
updating: a.txt (stored 0%)

削除されたファイルを反映する

上記の -uオプションはファイルを変更したり新規に追加したりした場合は期待通り動作します。 しかしファイルが削除された場合には zip を更新しません。 たとえとして、ここでは a.txt を不要になったとしてファイルを削除した場合を考えてみます。

この状態で上述の -u オプションを使っても backup.zip からは a.txt は削除されません。 つまりファイルの状態と zip 内の状態が不一致になってしまいます。 backup.zip からも削除したい場合は-d(--delete)オプションを使うことで backup.zip 内からファイルを削除できます。

ですがこの場合はいちいち削除されたファイルを指定する必要があり、ファイル数が多い場合には漏れが出るかもしれません。 そこで今回は --filesyncオプションを使います。 これは名前の通り自動的にファイルの状態を同期してくれます。 a.txtが削除された状態で --filesync を使うと backup.zip から自動で a.txtを削除してくれます。

下記の例には書いていませんが、ファイル更新があればもちろん -uと同じように zip 内のファイルも更新します。 バックアップを取るという目的ならこちらのほうが便利かと思います。

1
2
3
4
$ rm -r a.txt
$ zip -r -u backup.zip ./* # a.txt が削除されても test.zip はなにも更新されない
$ zip -r --filesync backup.zip ./* # a.txt が削除されているので backup.zip からも a.txt が削除される
deleting: a.txt

zipのなかにディレクトリを作りたくない場合

オプション -r でサブディレクトリごと圧縮した場合は、ディレクトリ構成を保持したまま圧縮されます。 下記の例では foo ディレクトリごと圧縮されています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ zipinfo backup.zip
Archive:  backup.zip
Zip file size: 876 bytes, number of entries: 6
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:43 a.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:31 b.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:31 c.txt
drwxr-xr-x  3.0 unx        0 bx stor 25-Jun-12 10:32 foo/
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:32 foo/fuga.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:32 foo/hoge.txt
6 files, 0 bytes uncompressed, 0 bytes compressed:  0.0%

もしディレクトリを含めたくない、サブディレクトリ以下のファイル含めてすべてのファイルがトップにある状態で圧縮したい場合は –junk-paths オプションが有用です。 下記の例では –junk-pathsを使って圧縮した場合、 fooディレクトリ自体は含まれず、そのfooディレクトリの下にあったfuga.txt, hoge.txtが含まれています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ zip --junk-paths -r --latest-time --must-match --filesync backup.zip ./
$ zipinfo backup.zip
Archive:  backup.zip
Zip file size: 724 bytes, number of entries: 5
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:43 a.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:31 b.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:31 c.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:32 fuga.txt
-rw-r--r--  3.0 unx        0 bx stor 25-Jun-12 10:32 hoge.txt
5 files, 0 bytes uncompressed, 0 bytes compressed:  0.0%

うっかり意図しないファイルを圧縮するのを防ぐ

zipコマンドに存在しないファイルを指定してもエラーにはなりません。 Warningが出るのみです。うっかりファイル名を間違えてもエラーにならないので少し危ないです。

1
2
3
$ zip -r --filesync backup.zip ./ none.txt
zip warning: name not matched: none.txt
Archive is current

あらかじめファイル名がわかっているときは --must-matchオプションが有用です。 指定したファイルが見当たらないときはWarningではなくエラーにしてくれます。

1
2
3
4
5
$ zip -r --must-match --filesync backup.zip ./ none.txt
zip warning: name not matched: none.txt
zip I/O error: No such file or directory
zip error: File not found or no read permission (none.txt)
/code>

ワイルドカードを使う場合はもちろん効果が弱まるのでご注意を。

まとめ

今回はファイルバックアップに便利な zip の --filesyncオプションを紹介しました。 ググってもこのオプションはあんまりヒットしないようなので、詳細はman zip で確認するのがいいかと思います。