Как я могу вносить изменения только в первую строку файла?

Я хотел бы знать, какой шаблон я могу использовать в sed для внесения изменений в первую строку огромных файлов (~ 2 ГБ). Предпочтение sed - только потому, что я предполагаю, что он должен быть быстрее, чем Python или Perl script.

Файлы имеют следующую структуру:

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

и, учитывая вероятность наличия пробелов в идентификаторе для каждого поля, мне нужно заменить каждое пространство символом подчеркивания следующим образом:

**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

Любые указатели на правильный шаблон для использования или другое решение для создания скриптов было бы замечательным.

Ответ 1

Чтобы отредактировать первые 10 строк

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

В Perl вы можете использовать оператор триггера в скалярном контексте:

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

Ответ 2

Я не думаю, что вы хотите использовать любое решение, которое требует, чтобы данные записывались в новый файл.

Если вы уверены, что все, что вам нужно, это изменить пробелы в символах подчеркивания в первой строке больших текстовых файлов, вам нужно только прочитать первую строку, поменять символы и записать их на место:

#!/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;

Чтобы использовать его, просто передайте полный путь к обновляемому файлу:

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

Ответ 3

Вы вряд ли заметите разницу в скорости между Perl, Python, и sed. Ваш script будет проводить большую часть своего времени, ожидая ввода-вывода.

Если строки имеют одинаковую длину, вы можете редактировать их на месте, иначе вы должен будет создать новый файл.

В 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: $!";

Ответ 4

упомянутое изменение (заменяя каждое пространство символом подчеркивания) не меняет длину строки, поэтому теоретически это можно сделать на месте.

предупреждение!: untested!

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

Я не уверен в параметрах conv=..., но кажется, что он должен сделать dd переписать начало исходного файла с преобразованной строкой.

обратите внимание, что если вы хотите сделать любое другое преобразование, которое может изменить длину строки, не делайте этого. вам нужно будет сделать полную копию. что-то вроде этого:

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

Ответ 5

Это может быть решение:


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

Tie:: File является одним из модулей, которые я использую больше всего, и он очень прост в использовании. Каждый элемент массива - это строка в файле. Однако одним из недостатков будет то, что он загружает весь файл в память.