awk :разделить файл по имени столбца и добавить строку заголовка в каждый файл

У меня возникла эта ошибка после импорта виртуальной машины. Решение состоит в том, чтобы исправить адрес HW в файле /etc/sysconfig/network -scripts/ifcfg -ens32 (ens32 оказался моим интерфейсом. Вы можете проверить свой с помощью Network Manager с файлом nmtui ).

Введите «ip-адрес» и запишите аппаратный адрес вашего интерфейса, например 00 :50 :56 :8d :6a :9e. Найдите интересующий вас интерфейс. из списка, который вы получаете от «ip addr».

Откройте для редактирования ваш /etc/sysconfig/network -scripts/ifcfg -ens32 (измените ifcfg -ens32 на имя вашего интерфейса, как указано выше, получите его из nmtui )и измените его адрес рядом с ключом HWADDR.

Теперь :перезапуск сервисной сети

6
21.09.2020, 12:15
2 ответа

Решение состоит в том, чтобы сохранить заголовок в отдельной переменной и распечатать его при первом появлении нового $1значения (= имени файла):

awk -F'|' 'FNR==1{hdr=$0;next} {if (!seen[$1]++) print hdr>$1; print>$1}' a.txt 
  • При этом вся первая строка a.txtбудет сохранена в переменной hdr, но в противном случае эта конкретная строка останется необработанной.
  • Во всех последующих строках мы сначала проверяем, встречалось ли уже $1значение (= желаемое имя выходного файла ), просматривая его в массиве seen, который содержит количество вхождений различных $1значений. Если счетчик по-прежнему равен нулю для текущего значения $1, выведите заголовок в файл, указанный $1, затем увеличьте значение счетчика, чтобы подавить вывод заголовка для всех последующих случаев. Остальное вы уже поняли сами.

Приложение:

Если у вас есть более одного входного файла, каждый из которых имеет строку заголовка, вы можете просто поместить их все в качестве аргументов вызова awk, как в

awk -F'|' '... ' a.txt b.txt c.txt...

Однако, если только первый файл имеет строку заголовка, вам нужно изменить FNRна NRв первом правиле.

Внимание

Как отмечает Эд Мортон,простой подход работает только в том случае, если количество различных выходных файлов невелико (макс. около 10 ). GNU awkпо-прежнему будет работать, но станет медленнее из-за автоматического закрытия и открытия файлов в фоновом режиме по мере необходимости; другие реализации awkмогут просто дать сбой из-за "слишком большого количества открытых файлов".

6
18.03.2021, 23:03

Это будет надежно и эффективно работать с любыми awk, sort и cut:

$ cat tst.sh
#!/usr/bin/env bash

awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' "$@" |
sort -t'|' -k1,1n -k2,2 -k3,3n |
cut -d'|' -f4- |
awk '
    BEGIN { FS=OFS="|" }
    NR == 1 { hdr = $0; next }
    $1 != prev {
        close(prev)
        print hdr " > " $1
        prev = $1
    }
    { print $0 " > " $1 }
'

$./tst.sh a.txt
filename|count|age > 1.txt
1.txt|1|15 > 1.txt
1.txt|2|14 > 1.txt
filename|count|age > 2.txt
2.txt|3|1 > 2.txt
2.txt|1|3 > 2.txt
filename|count|age > 41.txt
41.txt|44|1 > 41.txt

Измените " > "на просто >, чтобы фактически создавать выходные файлы после завершения тестирования.

Ведущий awk|sort|cut группирует все входные строки по имени файла ($1 )таким образом, что конечный awk обрабатывает содержимое только для 1 выходного файла за раз, поэтому он имеет только 1 выходной файл. открываются одновременно и поэтому не будут давать сбой с ошибкой "слишком много открытых имен файлов", когда дюжина или около того выходных файлов создаются в не -gawk или работают медленнее из-за жонглирования открытием/закрытием выходных файлов с помощью gawk.

Вот что происходит на каждом из предыдущих этапов, когда настраиваются данные для окончательного сценария awk, чтобы иметь возможность анализировать их, одновременно открывая только 1 выходной файл и сохраняя исходный порядок ввода для каждого имени выходного файла. основа:

$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt
0|filename|1|filename|count|age
1|1.txt|2|1.txt|1|15
1|1.txt|3|1.txt|2|14
1|2.txt|4|2.txt|3|1
1|41.txt|5|41.txt|44|1
1|2.txt|6|2.txt|1|3

$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt |
    sort -t'|' -k1,1n -k2,2 -k3,3n
0|filename|1|filename|count|age
1|1.txt|2|1.txt|1|15
1|1.txt|3|1.txt|2|14
1|2.txt|4|2.txt|3|1
1|2.txt|6|2.txt|1|3
1|41.txt|5|41.txt|44|1

$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt |
    sort -t'|' -k1,1n -k2,2 -k3,3n |
    cut -d'|' -f4-
filename|count|age
1.txt|1|15
1.txt|2|14
2.txt|3|1
2.txt|1|3
41.txt|44|1
3
18.03.2021, 23:03

Теги

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