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

В GNU sed :

sed -e '1i ;;' -e '$a ;;'

Он состоит из двух sed выражений:

  • 1i ;; вставляет ( i ) ;; (вставлена ​​новая строка) перед первой строкой ( 1 )

  • $ a ;; добавляет ( a ) ;; (новая строка встроена) после последней строки ( $ )

Пример:

$ cat foo.txt
sdas
adas

$ sed -e '1i ;;' -e '$a ;;' foo.txt 
;;
sdas
adas
;;

Поскольку у вас есть все файлы в add.txt , предполагается, что имя файла не содержит никаких символов из IFS (пробел, табуляция, новая строка по умолчанию) или подстановочных знаков ( * , ? , []), вы можете сделать следующее, чтобы отредактировать файлы с расширением .bak в качестве резервной копии оригинала:

sed -i.bak -e '1i ;;' -e '$a ;;' -- $(cat add.txt)

Без резервной копии:

sed -i -e '1i ;;' -e '$a ;;' $(cat add.txt)

Когда используется -i , файлы берутся отдельно вместо одного поток, так что нам хорошо идти. Без -i нам нужно использовать параметр -s , чтобы получить отдельные потоки для файлов.

Или прочтите имена файлов, разделенные новой строкой, и выполните операции одно за другим с резервным копированием:

while IFS= read -r f; do sed -i.bak -e '1i ;;' -e '$a ;;' -- "$f"; done <add.txt

без резервного копирования:

while IFS= read -r f; do sed -i -e '1i ;;' -e '$a ;;' -- "$f"; done <add.txt
2
22.08.2017, 14:21
3 ответа

Задание для 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
4
27.01.2020, 21:53

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 }-инициализация следующего нового имени файла(c++)при следующих 3 уникальных значениях.(delete a-удалить все элементы из массива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
1
27.01.2020, 21:53
#!/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
1
27.01.2020, 21:53

Теги

Похожие вопросы