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

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

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

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

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


person Alex. S.    schedule 14.02.2009    source источник


Ответы (5)


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

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

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

perl -i -pe 's/ /_/g if 1 .. 10'
person Leon Timmermans    schedule 14.02.2009
comment
Этому re нужен g в конце, чтобы заменить все пробелы в строке, а не только первый. - person Josh Lee; 14.02.2009
comment
perl -i -pe 's/ /_/g если 1 .. 10' ??? Вау, я никогда не слышал об этом синтаксисе в if 1..10. Иногда меня немного раздражает Perl. Почему все эти исключения? Почему бы просто не использовать простой if($. ‹ 11)? - person Frank; 14.02.2009
comment
@dehmann это оператор триггера, см. perldoc.perl.org/perlop.html очень удобно - person szabgab; 16.02.2009
comment
Хотя можно получить ответ, почему на самом деле не упоминается, как изменить только первую строку, как задан вопрос? за неимением лучшего способа я прибегнул к: perl -i -pe 's| ||g если 1 .. 1' - person goodguy5; 07.03.2016

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

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

#!/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"
person Renaud Bompuis    schedule 14.02.2009
comment
Это открытое || die неверна, оценивается как открытие FH, (+‹ $filename || die не может открыть $filename: $!); Используйте или или заключайте в скобки параметры open или оба: open( FH, +‹ $filename) или die can't open $filename: $!; - person szabgab; 16.02.2009
comment
Это должно было стать и моим решением. +1 - person Axeman; 16.02.2009

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

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

В Перле:

#!/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: $!";
person jrockway    schedule 14.02.2009
comment
Привет, можешь объяснить, почему в $first_line хранится только первая строка? - person One Face; 11.04.2016

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

Внимание!: не проверено!

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
person Javier    schedule 14.02.2009

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


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

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

person Geo    schedule 14.02.2009
comment
на самом деле он не загрузит файл, если в этом нет необходимости, поэтому, если вы измените только первую строку, а количество символов не изменится, это не будет иметь больших накладных расходов. - person szabgab; 16.02.2009
comment
Я думаю, что довольно редко бывает одинаковое количество символов после модификации строки. - person Geo; 16.02.2009