2009-02-14 13 views
10

Chciałbym wiedzieć, jaki wzór mogę użyć w sed do wprowadzania zmian w pierwszej linii ogromnych plików (~ 2 GB). Preferencja dla sed jest tylko dlatego, że zakładam, że musi być szybszy niż skrypt Python lub Perl.Jak mogę wprowadzić zmiany tylko do pierwszego wiersza pliku?

Pliki mają następującą strukturę:

field 1, field 2, ... field n 
data 

a biorąc pod uwagę prawdopodobieństwo konieczności spacje w identyfikator dla każdego pola, muszę wymienić każdą przestrzeń przez podkreślenie w ten sposób:

**BEFORE** 
the first name,the second name,the first surname,a nickname, ... 
data 

**AFTER** 
the_first_name,the_second_name,the_first_surname,a_nickname, ... 
data 

Wszelkie wskaźniki do właściwego wzoru do użycia lub inne rozwiązanie skryptowe byłoby świetne.

Odpowiedz

19

Aby edytować pierwsze 10 wierszy

sed -i -e '1,10s/ /_/g' 

W Perl, można użyć operatora flip-flop w kontekście skalarnym:

perl -i -pe 's/ /_/g if 1 .. 10' 
+0

Że re potrzebuje 'g' na końcu, aby zastąpić wszystkie spacje w linii, a nie tylko pierwsze. –

+1

perl -i -pe 's// _/g jeśli 1 .. 10' ??? Wow, nigdy nie słyszałem o tej składni w "if 1..10". Czasami denerwuje mnie Perl. Dlaczego wszystkie te wyjątki? Dlaczego nie po prostu użyć prostego, jeśli ($. <11)? – Frank

+0

@leon: wow, bardzo schludna sztuczka !, dziękuję. –

5

Jest mało prawdopodobne, aby zauważyć różnicę prędkości między Perl, Python, i sed. Twój skrypt poświęci większość czasu na oczekiwanie na IO.

Jeśli linie są tej samej długości, można edytować w miejscu, w przeciwnym razie będzie musiał utworzyć nowy plik.

W Perl:

#!/usr/bin/env perl 
use strict; 

my $filename = shift; 
open my $in_fh, '<', $filename 
    or die "Cannot open $filename for reading: $!"; 
my $first_line = <$in_fh>; 

open my $out_fh, '>', "$filename.tmp" 
    or die "Cannot open $filename.tmp for writing: $!"; 

$first_line =~ s/some translation/goes here/; 

print {$out_fh} $first_line; 
print {$out_fh} $_ while <$in_fh>; # sysread/syswrite is probably better 

close $in_fh; 
close $out_fh; 

# overwrite original with modified copy 
rename "$filename.tmp", $filename 
    or warn "Failed to move $filename.tmp to $filename: $!"; 
+0

Witam, czy możesz wyjaśnić, dlaczego tylko pierwsza linia jest przechowywana w '$ first_line'? –

4

zmiana wspomnieć (zastępując każdą przestrzeń przez podkreślenie) nie zmienia się długość tej linii, więc teoretycznie można to zrobić inplace.

ostrzeżenie !: nietestowane!

head -n 1 yourfile | sed -e 's/ /_/g' > tmpfile 
dd conv=nocreat,notrunc if=tmpfile of=yourfile 

nie jestem tak pewny o parametrach conv=..., ale wydaje się, że powinien zrobić dd nadpisać początek oryginalnego pliku z przekształconej linii.

należy pamiętać, że jeśli chcesz wykonać dowolne inne przekształcenie, które może zmienić długość linii, nie rób tego, , nie rób tego:. musiałbyś wykonać pełną kopię. coś takiego:

head -n 1 yourfile | sed -e 's/ /_/g' > tmpfile 
tail -n + 2 | cat tmpfile - > transformedfile 
9

nie wiem myślę, że chcesz użyć dowolnego rozwiązania, które wymaga zapisania danych w nowym pliku.

Jeśli jesteś prawie pewien, że wystarczy zmienić spacje w podkreślenia w pierwszym wierszu dużych plików tekstowych, musisz tylko przeczytać pierwszy wiersz, zamienić znaki i zapisać je z powrotem w miejscu:

#!/usr/bin/env perl 
use strict; 

my $filename = shift; 
open (FH, "+< $filename") || die "can't open $filename: $!"; 
my $line = <FH>; 
$line =~ s/ /_/g; 
seek FH, 0, 0; # go back to the start of the file 
printf FH $line; 
close FH; 

aby go użyć, wystarczy przekazać pełną ścieżkę pliku do aktualizacji:

# fixheader "/path/to/myfile.txt" 
+0

To jest otwarte || kostka jest niepoprawna, ocenia się na otwórz FH, ("+ szabgab

+0

To prawda, dziękuję za zauważenie błędu. –

+0

To też miało być moje rozwiązanie. +1 – Axeman

-1

To może być rozwiązanie:

 

use Tie::File; 
tie my @array,"Tie::File","path_to_file"; 
$array[0] = "new text"; 
untie @array; 
 

Tie::File to jeden z modułów, z których korzystam najbardziej i jest bardzo prosty w użyciu. Każdy element w tablicy jest linią w pliku. Jedną z wad jest jednak to, że ładuje cały plik w pamięci.

+0

w rzeczywistości nie załaduje pliku, jeśli nie musi, więc jeśli zmienisz tylko pierwszy wiersz, a liczba znaków się nie zmieni, to nie będzie to miało większego narzutu. – szabgab

+0

Wydaje mi się, że dość rzadko występuje taka sama liczba znaków po modyfikacji linii. – Geo

Powiązane problemy