Создание категории, если она не существует, распечатать текущие данные, если она существует

У меня есть несколько текстовых файлов со строками категорий и числовыми данными для каждой категории. Хотя существует ограниченное количество категорий, скажем, от a до g, не все файлы имеют каждую категорию, например:

file1:

a 199
b 20
c 70
e 1
f 200

file2:

a 11
b 103
c 232
d 92
f 7
g 201

file3:

a 100
b 120
c 9
d 20
e 33
f 123
g 9191

Я хотел бы создать выходные файлы так, чтобы, если категория уже существовала, воспроизводилась строка, но если категория не существовала, категория создавалась с числовым значением 0. Я подумал об использовании

$ awk '$1 ~ /category/ {print $0}'

для категорий, которые уже существуют, но я не уверен, как представить новые.

Любое решение, даже если оно не с awk, будет оценено.

Благодарю.

3 ответа

Решение

Допустим, у вас также есть файл с категориями:

$ cat categories
a
b
c
d
e
f
g

Предположим также, что все категории являются простыми словами без пробелов и что все ваши файлы отсортированы по столбцу категории. РЕДАКТИРОВАТЬ: На самом деле, любая строка категории идет, но вам будет лучше использовать разделитель, как табуляцию или запятую или что-то в ваших файлах, в этом случае добавьте -t "," к join Команда ниже (если вы используете запятые, которые есть). Смотрите конец ответа для примера.

Тогда это решит вашу проблему:

$ join -a 1 -o 1.1,2.2 -e 0 categories file1
a 199
b 20
c 70
d 0
e 1
f 200
g 0

join Утилита выполняет операцию реляционного соединения над первым столбцом (по умолчанию) двух файлов. Здесь мы кормим его categories файл и первый пример файла.

-a 1 опция говорит "дай мне все строки из первого входного файла (categories), даже если они не совпадают со строками во втором файле (file1)".

-o 1.1,2.2 опция говорит: "Я хотел бы видеть столбец 1 из первого файла и столбец 2 из второго файла в выводе".

-e 0 опция говорит "замените все пропущенные значения на 0".

РЕДАКТИРОВАТЬ: Помните, что оба входных файла join должны быть отсортированы по полю, которое мы используем для выполнения объединения (первое поле всех файлов в этом случае, так что просто sort -o file file на каждый файл сделаю). Если файлы не были отсортированы, то join потребуется прочитать их в память, и, как и многие другие инструменты Unix, это не так, как это было реализовано. Вместо этого это быстрый и эффективный инструмент памяти, который предъявляет лишь немного более строгие требования к своим входным данным. Эти ограничения легко обрабатываются другими инструментами (sort). Это философия Unix в действии.

РЕДАКТИРОВАТЬ: Пример с несколькими словами категории:

$ cat categories
a category
b nice
c at
d cide
e ffective
f ull of gas
g one

$ cat file1
a category,199
b nice,20
c at,70
e ffective,1
f ull of gas,200

$ join -t "," -a 1 -o 1.1,2.2 -e 0 categories file1
a category,199
b nice,20
c at,70
d cide,0
e ffective,1
f ull of gas,200
g one,0

С помощью file1 В качестве примера:

$ awk '{a[$1]=$2} END{split("abcdefg",b,//); for (i in b) print b[i],a[b[i]]+0}' file1
a 199
b 20
c 70
d 0
e 1
f 200
g 0

Как это устроено

  • a[$1]=$2

    Для каждой прочитанной строки мы сохраняем значение в столбце в ассоциативном массиве a с категорией (столбец 1) в качестве ключа.

  • END{split("abcdefg",b,//); for (i in b) print b[i],a[b[i]]+0}

    После того, как мы закончили чтение файла, мы создаем массив b который имеет в качестве значений все категории. таким образом b[1] является a а также b[3] является c, так далее.

    Далее для каждого элемента в bраспечатываем сохраненное в массиве значение a, Если значение не было сохранено в a, затем awk дает нам значение по умолчанию. Чтобы убедиться, что значение по умолчанию равно нулю, в отличие от пустой строки, мы добавляем 0 к значению в a что заставляет awk рассматривать значение в a как число.

Обработка многобуквенных категорий

Давайте рассмотрим этот тестовый файл:

$ cat file2
category1 1
category2 2

Теперь давайте проанализируем его по трем категориям:

$ awk '{a[$1]=$2} END{split("category1_category2_category3",b,"_"); for (i in b) print b[i],a[b[i]]+0}' file2
category1 1
category2 2
category3 0

Если вы хотите сохранить заказ:

awk 'BEGIN{
    split("a b c d e f g",p);
    i=1
}
p[i]!=$1{
    print p[i],0;
    i++
}
{
    i++;
    print
}
END{
    for (j=i;j<=7;j++)print p[j],0
}' file
Другие вопросы по тегам