Як розділити великий файл на дві частини за шаблоном?
Наведений приклад 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/
буде silently розбити файл, створюючи шматки попередньо fIX 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- -unbuferi 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слід включати рядок у висновок чи ні?