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


Я хотел бы знать, какой шаблон я могу использовать в 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

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

5 10

5 ответов:

Для редактирования первых 10 строк

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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