Intereting Posts

UNIX – команда разбивать файл на несколько файлов со всеми строками для каждых 3 уникальных значений в столбце

Рассмотрим приведенный ниже входной файл. Входной файл:

C1|C2|C3|C4|C5|C6 0|1|2|3|0-1-2-3|4 0|2|2|4|0-1-2-3|5 0|1|2|3|1-3-2-4|4 0|1|2|3|1-1-3-4|4 0|1|2|3|1-1-3-4|5 0|1|2|3|4-5-2-6|4 0|1|2|3|4-5-2-6|6 0|4|5|3|7-4-2-4|4 0|1|2|3|7-4-2-5|4 0|1|2|3|7-4-2-5|5 0|1|2|3|7-4-2-5|6 0|1|2|3|7-5-2-6|5 

Основываясь на поле 5, например 0-1-2-3 в первой записи, ожидается, что файлы разделенных файлов будут разделены следующим образом: Split file1:

 C1|C2|C3|C4|C5|C6 0|1|2|3|0-1-2-3|4 0|2|2|4|0-1-2-3|5 0|1|2|3|1-3-2-4|4 0|1|2|3|1-1-3-4|4 0|1|2|3|1-1-3-4|5 

Разделить файл 2:

 C1|C2|C3|C4|C5|C6 0|1|2|3|4-5-2-6|4 0|1|2|3|4-5-2-6|6 0|4|5|3|7-4-2-4|4 0|1|2|3|7-4-2-5|4 0|1|2|3|7-4-2-5|5 0|1|2|3|7-4-2-5|6 

Разделить файл 3:

 C1|C2|C3|C4|C5|C6 0|1|2|3|7-5-2-6|5 

Основываясь на столбце 5, для каждых 3 уникальных значений в столбце файл должен быть разделен и должен иметь даже все строки, где значение столбца 5 повторяется. Может кто-то помочь мне с этим?

Работа для awk. Что-то вроде:

 awk -F'|' -v fileformat="/abc/output/file_%04d.txt" -v max=3 -v field=5 ' NR == 1 {header = $0; next} ! ($field in seen) { seen[$field] if (++n % max == 1) { close(out) out = sprintf(fileformat, ++f) print header > out } } {print > out}' < /abc/input/a.txt 

Решение awk :

 awk -F'|' 'NR==1{ h=$0; f=0; c=1 }NR>1{ a[$5]; if(length(a)>3) { f=0;c++; delete a }; fn="file"c".txt"; if(!f) print h > fn; print > fn; f++ }' file 
  • h=$0 – строка заголовка

  • f=0 – флаг, указывающий на момент печати строки заголовка в следующий новый файл

  • c=1 – суффикс имени файла (увеличивается для каждого нового файла)

  • a[$5] – индексный массив a с уникальными значениями 5-го поля

  • if(length(a)>3) { f=0;c++; delete a } if(length(a)>3) { f=0;c++; delete a } – запуск следующего нового имени файла ( c++ ) при достижении трех уникальных значений. ( delete a – удалить 11 элементов из массива a )

  • fn="file"c".txt" – текущее имя файла


Просмотр результатов:

 for f in file[0-9]*.txt; do echo "$f"; cat "$f"; echo; done 

Выход:

 file1.txt C1|C2|C3|C4|C5|C6 0|1|2|3|0-1-2-3|4 0|2|2|4|0-1-2-3|5 0|1|2|3|1-3-2-4|4 0|1|2|3|1-1-3-4|4 0|1|2|3|1-1-3-4|5 file2.txt C1|C2|C3|C4|C5|C6 0|1|2|3|4-5-2-6|4 0|1|2|3|4-5-2-6|6 0|4|5|3|7-4-2-4|4 0|1|2|3|7-4-2-5|4 0|1|2|3|7-4-2-5|5 0|1|2|3|7-4-2-5|6 file3.txt C1|C2|C3|C4|C5|C6 0|1|2|3|7-5-2-6|5 
 #!/bin/bash awk -F '|' ' function print_to_file(str) { print str > "file_"file_num; } NR == 1 {header = $0;} NR > 1 { if(!buf) { file_num = 1; print_to_file(header); } if(buf != $5) { buf = $5; cnt++; } if(cnt > 3) { cnt = 1; file_num++; print_to_file(header); } print_to_file($0); } ' input.txt 

Вывод:

 $ tail -n +1 -- file_* # display content of all files with their filenames ==> file_1 <== C1|C2|C3|C4|C5|C6 0|1|2|3|0-1-2-3|4 0|2|2|4|0-1-2-3|5 0|1|2|3|1-3-2-4|4 0|1|2|3|1-1-3-4|4 0|1|2|3|1-1-3-4|5 ==> file_2 <== C1|C2|C3|C4|C5|C6 0|1|2|3|4-5-2-6|4 0|1|2|3|4-5-2-6|6 0|4|5|3|7-4-2-4|4 0|1|2|3|7-4-2-5|4 0|1|2|3|7-4-2-5|5 0|1|2|3|7-4-2-5|6 ==> file_3 <== C1|C2|C3|C4|C5|C6 0|1|2|3|7-5-2-6|5