Ответ 1
Чтобы отредактировать первые 10 строк
sed -i -e '1,10s/ /_/g'
В Perl вы можете использовать оператор триггера в скалярном контексте:
perl -i -pe 's/ /_/g if 1 .. 10'
Я хотел бы знать, какой шаблон я могу использовать в 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
Любые указатели на правильный шаблон для использования или другое решение для создания скриптов было бы замечательным.
Чтобы отредактировать первые 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, и 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: $!";
упомянутое изменение (заменяя каждое пространство символом подчеркивания) не меняет длину строки, поэтому теоретически это можно сделать на месте.
предупреждение!: 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
Это может быть решение:
use Tie::File;
tie my @array,"Tie::File","path_to_file";
$array[0] = "new text";
untie @array;
Tie:: File является одним из модулей, которые я использую больше всего, и он очень прост в использовании. Каждый элемент массива - это строка в файле. Однако одним из недостатков будет то, что он загружает весь файл в память.