# Unzip über stdin



## DasArne (11. Dezember 2009)

Hallo zusammen,
ich habe immer das gleiche Problem:
Source runterladen, auspacken und dann das runtergeladene Paket wegwerfen.
Ich würde gerne einfach direkt auspacken. 

Mit Tar geht das ganz einfach:
Hier werden z.B. die Sourcen vom Apache runtergeladen und entpackt

```
curl http://artfiles.org/apache.org/httpd/httpd-2.2.14.tar.gz | tar xvzf -
```

Aber wie sieht das mit einem zip-file aus? unzip hat irgendwie keine Möglichkeit über stdin Daten anzunehmen. Gibt es einen Trick?

Viele Grüße
 Arne


----------



## Enumerator (8. Februar 2010)

Hi!

Leider geht das momentan nicht:





			
				man unzip hat gesagt.:
			
		

> Archives  read  from  standard  input  are not yet supported


.Leider ist es auch nicht möglich einfach /dev/stdin als Dateinamen anzugeben.
Auch wenn es nicht unbedingt die beste Lösung ist - das Perl-Skript unten erledigt den Job. Du kannst es z.b. unter /usr/local/bin/unzip ablegen, dann fungiert es automatisch als Wrapper für /usr/bin/unzip:
	
	
	



```
#!/usr/bin/perl

use strict;
use warnings;

my($ok, @command)= qw(1 /usr/bin/unzip);

sub usage {
    print STDERR `/usr/bin/unzip -h`;
    print STDERR <<"EOT;";

Anstelle des Dateinamens kann genau ein mal "--" verwendet werden.
In diesem Fall wird die Standard-Eingabe (STDIN) gelesen.
EOT;
    exit shift;
}

for(@ARGV) {
    usage 0 if $_ eq "-h";
    if($_ eq "--") {
        usage -1 unless $ok--;
        my $filename = `whoami`;
        chomp $filename;
        $filename = "/tmp/$filename.". time() .".zip";
        binmode STDIN or die $!;
        open FILE, ">", $filename or die $!;
        binmode FILE or die $!;
        while(my $line = <STDIN>) {
            print FILE $line;
        }
        push @command, $filename;
        close FILE;
    } else {
        push @command, $_;
    }
}

exec @command;
```
Das schaut dann etwa so aus:
	
	
	



```
lenny:~/test$ ls
unzip.pl  picknik-am-wegesrand.txt
lenny:~/test$ su
Passwort: 
lenny:/home/enum/test# ln -s `pwd`/unzip.pl /usr/local/bin/unzip
lenny:/home/enum/test# exit
exit
lenny:~/test$ zip test.zip picknik-am-wegesrand.txt 
  adding: picknik-am-wegesrand.txt (deflated 62%)
lenny:~/test$ ls
unzip.pl  picknik-am-wegesrand.txt  test.zip
lenny:~/test$ rm picknik-am-wegesrand.txt 
rm: reguläre Datei „picknik-am-wegesrand.txt“ entfernen? y
lenny:~/test$ unzip -- < test.zip 
Archive:  /tmp/enum.1265635053.zip
  inflating: picknik-am-wegesrand.txt  
lenny:~/test$ ls
unzip.pl  picknik-am-wegesrand.txt  test.zip
lenny:~/test$
```
Das Skript kann jetzt genauso wie unzip selbst verwendet werden, inklusive aller Argumente und anstelle eines Dateinamens kann jetzt "--" übergeben werden.
Einziger Nachteil ist das interaktive Benutzereingaben unterdrückt werden wenn wirklich von STDIN gelesen wird (z.B. die Frage nach dem überschreiben von Dateien).

Gruß
Enum


----------



## deepthroat (8. Februar 2010)

Hi.

@Enumerator: Du solltest lieber File:Temp (http://search.cpan.org/~jhi/perl-5.8.0/lib/File/Temp.pm) verwenden um temp. Dateinamen zu erstellen.

Ansonsten ist das entpacken eines Zip-Archivs direkt aus einem Stream schlecht möglich, da das Verzeichnis der Einträge sich am Ende der Datei befindet (siehe http://de.wikipedia.org/wiki/Datei:ZIPformat.jpg), also erstmal die gesamte Datei runtergeladen werden muss bevor man mit dem Entpacken beginnen kann.

Gruß


----------



## Enumerator (8. Februar 2010)

@deepthroat:

Klar, File::Temp, vor allem wenn's um Portabilität geht. Doch wir sind im Linux/Unix Forum...
So, genug gerechtfertigt  - jetzt mal im Ernst:
Ich wollte das ursprünglich als Shellskript regeln, bin aber am "binmode" gescheitert und habe das einfach stumpf in Perl übersetzt.
Kennst Du eine Möglichkeit, das doch ohne Perl zu schaffen?

Gruß
Enum


----------



## deepthroat (8. Februar 2010)

Enumerator hat gesagt.:


> @deepthroat:
> 
> Klar, File::Temp, vor allem wenn's um Portabilität geht. Doch wir sind im Linux/Unix Forum...


Wie meinst du das? Was hat das mit Linux/Unix zu tun wenn man aus Sicherheitsgründen File::Temp verwendet was ja auch unter Windows etc. funktioniert? Ich verstehe deine Aussage irgendwie nicht...


Enumerator hat gesagt.:


> Ich wollte das ursprünglich als Shellskript regeln, bin aber am "binmode" gescheitert und habe das einfach stumpf in Perl übersetzt.
> Kennst Du eine Möglichkeit, das doch ohne Perl zu schaffen?


Naja, mit Python 

Oder Bash

```
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
cat > "$tmp" && unzip "$@" "$tmp" || (echo "failed."; exit 1)
```
Gruß


----------



## Enumerator (9. Februar 2010)

deepthroat hat gesagt.:


> Was hat das mit Linux/Unix zu tun wenn man aus Sicherheitsgründen File::Temp verwendet was ja auch unter Windows etc. funktioniert?


Das Nicht-verwenden von File::Temp hat was mit Linux/Unix zu tun sondern wenn man es trotz Kenntnis einfach außer acht lässt. Der Grund? Ich bin im Linux & Unix Forum auf ein einigermaßen interessantes Problem gestoßen, hab' es auf meinem BSD-Läppi kurz ausprobiert, später auf dem Linux-Rechner noch ein wenig 'rumgespielt und bin nicht einmal auf die Idee gekommen, dass das mickrige Skript irgendwann mal auf einem anderen System landet. 

Ich muss mich doch bedanken, wieder einmal bin ich dank Dir ein wenig schlauer...
Ich weiß jetzt, dass cat ohne Argumente von der Standard-Eingabe liest und im Gegensatz zu einer while-read-do-echo-Schleife (*schäm*) Binärdaten nicht verstümmelt.
Danke!


----------

