19406


testファイルを作成して、gzipコマンドで圧縮すると、test.gzが作成されます。  
このtest.gzを拡張子を外した名前(test)に変更すると、gzipコマンドやgunzipコマンドで  
解凍することができないのですが、なぜでしょうか。

gunzip -S .gz test


CC BY-SA 3.0
2015-11-28T05:42:33.043
19392
2015-11-28T08:58:30.123
2015-11-28T06:14:31.977
76
7461
question
unix
拡張子gzを付けないとgzip(gunzip)コマンドで解凍できない


何故といわれると難しいのですが、圧縮ファイルには正しくサフィックスを付けるという設計からくる仕様と思われます。(`gunzip test` と実行して
test.gz が対象にされるという仕様があるので、都合が良いという理由もあるかもしれません。)

ちなみに、test という圧縮ファイルを展開したい場合には、`gzcat < test > test2` のように実行することが出来ます。


CC BY-SA 3.0
2015-11-28T06:13:52.523
19396
2015-11-28T06:13:52.523
76
19392
answer


ソースコード上では以下の様になっていて、gzip によって圧縮されたファイルに所定の拡張子(`".gz", ".z", ".taz", ".tgz",
"-gz", "-z", "_z"` のいずれか)が付いていない場合は復元処理を行いません。

**gzip-1.6/gzip.c**

[code]

    /* ========================================================================
     * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
     * Sets save_orig_name to true if the file name has been truncated.
     */
    local int make_ofname()
    {
        char *suff;            /* ofname z suffix */
    
        strcpy(ofname, ifname);
        /* strip a version number if any and get the gzip suffix if present: */
        suff = get_suffix(ofname);
    
        if (decompress) {
            if (suff == NULL) {
                /* With -t or -l, try all files (even without .gz suffix)
                 * except with -r (behave as with just -dr).
                 */
                if (!recursive && (list || test)) return OK;
    
                /* Avoid annoying messages with -r */
                if (verbose || (!recursive && !quiet)) {
                    WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
                          program_name, ifname));
                }
                return WARNING;
            }
    
[/code]

一方で、gzip の ChangeLog に以下の様な記述があります。

> Mon Jun 14 10:03:24 1993 Jean-loup Gailly (jloup@chorus.fr)
>
> * version 1.2  
>  Allow gunzip --suffix "" to attempt decompression on any file regardless of
> its extension if an original name is present.
>
> 2010-02-22 Jim Meyering
>
> gzip: fix a data-loss bug when decompressing with --suffix=''  
>  * gzip.c (main): Disallow an empty --suffix=S also with -d. Otherwise,
> "gzip -d -S '' F.gz" would ask if it's ok to remove the existing file,
> "F.gz"; if you reply "yes", you'd lose all of that data. Use of an empty
> suffix was already rejected in compression mode.

つまり、gzip 1.4 までは、

[code]

    $ gzip -d -S '' test
    
[/code]

とすれば復元処理を行うのですが、その前に対象ファイルを削除してしまう、という事です。実際に gzip 1.4 をコンパイルして試してみます。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test
    $ ls -l test
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ gzip-1.4 -d -S '' test
    gzip: test already exists; do you wish to overwrite (y or n)? 
    
[/code]

ここで `y` を入力してしまうと、確かにファイル `test` は消失してしまいます。

[code]

    $ ls -l test
    ls: cannot access test: No such file or directory
    
[/code]

ところで、名前(パス)が異なれば問題はないはずです。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test2
    $ gzip-1.4 -N -d -S '' test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ cat test
    Hello World
    
[/code]

もっとも、これでは意味がないですし、gzip 1.6 ではエラーになってしまいますので、やはり拡張子は付けるべきという事なのでしょう。

番外編として、[moreutils](https://joeyh.name/code/moreutils/) に含まれる `sponge` コマンドを使った
in place な復元方法を紹介しておきます。

[code]

    $ echo 'Hello World' > test
    $ gzip test
    $ mv test.gz test
    $ gunzip -c test | sponge test
    $ cat test
    Hello World
    
[/code]

`sponge` という名前から、何をしているのか分かるかと思います。


CC BY-SA 3.0
2015-11-28T08:58:30.123
19406
2015-11-28T08:58:30.123
19392
answer