Як розділити великий файл на дві частини за шаблоном?
Наведений приклад file.txt
:
ABC
EFG
XYZ
HIJ
KNL
Я хочу розділити цей файл на XYZ
такий, який file1
містить рядки вгору XYZ
та решта рядків у file2
.
Як розділити великий файл на дві частини за шаблоном?
Наведений приклад file.txt
:
ABC
EFG
XYZ
HIJ
KNL
Я хочу розділити цей файл на XYZ
такий, який file1
містить рядки вгору XYZ
та решта рядків у file2
.
Відповіді:
З awk
вами можна робити:
awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile
Пояснення: Перший awk
аргумент ( out=file1
) визначає змінну з ім'ям файлу, яка буде використовуватися для виведення під час largefile
обробки наступного аргументу ( ). awk
Програма буде друкувати всі рядки в файл , вказаний у змінній out
( {print >out}
). Якщо шаблон XYZ
буде знайдено, вихідну змінну буде переосмислено, щоб вказати на новий файл ( {out="file2}"
), який буде використовуватися як цільовий для друку наступних рядків даних.
Список літератури:
Це робота для csplit
:
csplit -sf file -n 1 large_file /XYZ/
буде s
ilently розбити файл, створюючи шматки попередньо f
IX file
і n
коричневого з використанням однієї цифри, наприклад , і file0
т.д. Зверніть увагу , що з допомогою /regex/
розділив би до, але не включаючи лінію, сірники regex
. Щоб розділити на та включити відповідність рядків, regex
додайте +1
зміщення:
csplit -sf file -n 1 large_file /XYZ/+1
Це створює два файли file0
та file1
. Якщо вам абсолютно потрібно, щоб вони були названі, file1
і file2
ви завжди можете додати порожній шаблон до csplit
команди та видалити перший файл:
csplit -sf file -n 1 large_file // /XYZ/+1
створює file0
, file1
і , file2
але file0
порожній , так що ви можете безпечно видалити його:
rm -f file0
З сучасним ksh
ось варіантом оболонки (тобто без sed
) однієї з наведених sed
вище відповідей:
{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1
І ще один варіант у ksh
самоті (тобто також опущення cat
):
{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1
(Чисте ksh
рішення здається досить ефективним; для тестового файлу об'ємом 2,4 ГБ було потрібно 19-21 сек. Порівняно з 39-47 сек. З підходом sed
/ cat
на основі).
read
і print
потрібно просто відпустити, щоб вивести все своє. Продуктивність покращується, якщо ви повністю складете інструментарій AST і отримаєте всі ksh
вбудовані складені файли - мені дивно, що sed
насправді це не одна з них. Але з такими речами, як while <file do
я думаю, вам не потрібно sed
так багато ...
awk
виступили у вашому бенчмарці? І хоча я майже впевнений, що ksh
, ймовірно, завжди виграє цю боротьбу, якщо ви використовуєте GNU, sed
ви не дуже справедливі sed
- -u
nbuferi GNU - це поганий підхід до POSIXLY, гарантуючи, що компенсація дескриптора залишиться там, де програма кинеться це - не повинно бути сповільнювати регулярну роботу програми - буферизація прекрасна - все, що sed
потрібно робити, - це шукати дескриптор, коли закінчите. З будь-якої причини GNU повертає цю ментальність.
while
; друк неявно робиться як визначений побічний ефект <##
оператора перенаправлення. І тільки друкована лінія потребує друку. (Таким чином, реалізація функції оболонки найбільш гнучка для підтримки incl./excl.) Явний while
цикл, який я очікував би, буде значно повільнішим (але не перевіряв).
head
замість цього read
; це здається лише трохи повільніше, але це більш короткий код : { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3
.
Спробуйте це за допомогою GNU sed:
sed -n -e '1,/XYZ/w file1' -e '/XYZ/,${/XYZ/d;w file2' -e '}' large_file
sed -e '1,/XYZ/{w file1' -e 'd}' large_file > file2
Легкий злом - це надрукувати або STDOUT, або STDERR, залежно від того, чи відповідає цільова картина. Потім можна використовувати оператори перенаправлення оболонки, щоб відповідно перенаправити вихід. Наприклад, в Perl, припускаючи, що вхідний файл викликається f
і двома вихідними файлами, f1
і f2
:
Відхилення лінії, що відповідає шаблону розбиття:
perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
У тому числі відповідна лінія:
perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
Крім того, друкуйте на різні ручки файлів:
Відхилення лінії, що відповідає шаблону розбиття:
perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
У тому числі відповідна лінія:
perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
$a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
XYZ
слід включати рядок у висновок чи ні?