On Friday 19 May 2006 11:50, GUNREBEN, PETER (Peter) wrote:
Was meinst Du damit? Dominik hat doch das Problem, dass er auf der Platte keine 12 GByte reservieren will, nur damit er die 6 GByte grosse Datei umkopieren kann. Über die "buffer" Lösung wird ja lediglich ein Teil der Datei im RAM gehalten und auf der Platte werden nur 6 GByte benötigt.
Wie sieht buffer aus? Könnte man STDIN auch einfach mittels exec auf STDOUT umleiten, um es in die pipe zu geben?
Kannst Du 'mal genauer erklären, was Du vor hast?
Ich muss uebrigens leider zugeben, dass meine Lösung wirklich nicht sicher ist und daher mit Vorsicht zu geniessen ist. Das Problem ist, dass "cat ToPrependFile.txt" unter Umständen schon anfängt zu schreiben, bevor der buffer die Datei im Speicher hat. Um das zu verhindern habe ich folgendes probiert:
cat ToPrependFile.txt LargeFile.txt | buffer -p 100 > LargeFile.txt
Leider funktioniert die obige Zeile auch nicht sicher, wobei ich nicht verstehe, warum. Die "-p 100" Option sollte den buffer dazu bringen, erst dann zu schreiben, wenn der buffer voll ist (default 1 MByte). Wenn nun ToPrependFile.txt deutlich kleiner als 1 MByte ist, hätte ich erwartet, dass es problemlos funktioniert. Das ist aber leider nicht der Fall.
Hat jemand eine Erklärung?
1) ja, ">LargeFile.txt" kürzt das File auf 0 Bytes bevor irgendwas anderes passiert. 2) Du liest und schreibst nach LargeFile.txt gleichzeitig, wobei der Lesezeiger kleiner als der Schreibezeiger ist. Du liest aber, bis ein End-of-File auftaucht. Ohne Buffering kann das eigentlich nicht passieren. D.h. die Größe Deines Output-Files ist ziemlich zufällig. Hier eine Lösung die funktioniert. Ich habe es mit einem 5GB File namens 'big' und einem 1MB 'prefix' unter Suse 10.0 (32bit) getestet. Ich hatte dazu alles in eine Zeile geschrieben und den Backslash am Ende der vorletzten Zeile weggelassen. perl -e 'my $prefix=shift; my $file=shift; $prefix=do {local $/; local @ARGV=($prefix); <>}; my $fs=(stat($file))[7]; $/=\length $prefix; open my $f, $file; while( my $buf=<$f> and $fs>0 ) { print $prefix; $prefix=$buf; $fs-=length $buf; $/=\$fs if(${$/}>$fs); } print $prefix' \ prefix big 1<>big Erklärung: "1<>big" am Ende öffnet STDOUT zum Lesen und Schreiben. Damit wird das Output-File nicht schon von der Shell gelöscht und so das erste Problem behoben. Mit der Option -e kann man dem Perl-Interpreter im nächsten Argument ein Kommando übergeben, ähnlich wie "bash -c ...". Perl wird hier mit 4 Parametern aufgerufen: 1) -e, 2) das Kommando 3) das Prefix-File prefix, 4) das große File big. Die Output-Umleitung wird komplett von der Shell bearbeitet. Perl bekommt das nicht mit. Die ersten 2 Zeilen des Kommandos lesen die Parameter prefix und big ein und speichern sie in den Variablen $prefix und $big. Die 3. Zeile liest das prefix-File dann vollständig in die Variable $prefix ein. Zeile 4 ermittelt die Größe in Bytes von 'big'. Zeile 5 setzt die Input-Buffer Größe ($/) auf die Länge des Prefix. Ziel ist es immer einen solchen Block zwischen Lese- und Schreibezeiger Platz zu lassen. Dann öffne ich das Input-File 'big'. Der Zyklus, der in Zeile 7 beginnt, liest 'big' nun blockweise ein. Das Ende ist erreicht, wenn entweder keine Daten mehr da sind oder die Größe der noch zu lesenden Daten ($fs) kleiner oder gleich 0 wird. In Zeile 8 wird der aktuelle Prefix (oder Output-Buffer) ausgegeben. Da $prefix nun nicht mehr benötigt wird, kann die Variable mit dem gerade gelesenen Block in Zeile 9 überschrieben werden. In Zeile 10 wird nun die gelesene Länge von der Gesamtlänge ($fs) abgezogen. Falls $fs nun kleiner als die Blockgröße wurde, ist eigentlich das Ende erreicht. Das Programm muss noch einen Block einlesen, der aber kleiner als die normale Blockgröße ist. Also wird die Blockgröße auf diesen Wert gesetzt. Nach dem Zyklus in Zeile 13 enthält $prefix noch einen noch nicht geschriebenen Block. Dieser muss also noch ausgegeben werden. Das war's. Zum Test: (dd if=<(yes) bs=1k count=5242880; echo y) >big dd if=<(yes n) bs=1k count=1024 >prefix Jetzt enthält big 2684354561 Zeilen bestehend aus 2 Zeichen: "y\n" und prefix 524288 Zeilen "n\n". big ist damit 2 Bytes größer als 5GiB, prefix genau 1MiB groß: r2@ikra:~> ls -l big prefix -rw-r--r-- 1 r2 users 5368709122 2006-05-19 15:39 big -rw-r--r-- 1 r2 users 1048576 2006-05-19 14:12 prefix Während nun das Programm läuft ändert sich die Größe von big übrigens nicht. Es bleibt die meist Zeit 5GiB+2Bytes groß. Erst am Schluß wächst es. Nach dem Perl-Programm ist big um genau ein MiB gewachsen: r2@ikra:~> ls -l big -rw-r--r-- 1 r2 users 5369757698 2006-05-19 16:04 big r2@ikra:~> bc -lq 5369757698-5368709122 1048576 Zur Kontrolle, ob die Bytes auch wirklich so liegen, wie sie sollen, können wir aufgrund der Struktur von big und Prefix das Kommando "uniq -c" benutzen. Es zählt gleiche benachbarte Zeilen und gibt die Summe jeweils eines Blocks gleicher Zeilen aus: r2@ikra:~> uniq -c big 524288 n 2684354561 y Torsten