Объединить два файла плюс второй столбец с помощью AWK

Awk выдает ошибку, потому что переменная "c" установлена равной пустой переменной. $maximum еще не установлен.

Вы должны сделать:

awk -v c=`cat maximum` '{print $1/c}' CVBR1_hist > CVBR1_norm

Вот где ваша команда потерпела неудачу.

Лучший способ: не обращаться к временному файлу, а хранить максимальное значение в переменной, как в ответе Кусалананды.

1
11.12.2016, 05:45
2 ответа

Теперь, когда я увидел ваше исследование, я даю вам свое решение:

awk '{ z[$1]=z[$1]$2 } END { for (i in z) print i, z[i] }' file1  file2

вывод:

002 BD
003 CD
004 D
005 E
006 F 
001 A

Если вы хотите выполнить числовую сортировку значений первого столбца, вы можете передать вывод предыдущей команды в sort :

awk '{ z[$1]=z[$1]$2 } END { for (i in z) print i, z[i] }' file1  file2 \
| sort -n -k1
0
27.01.2020, 23:34

Левое / правое внешнее объединение против полного внешнего объединения

Проблема с командой, которую вы используете, заключается в том, что она требует, чтобы все записи в файле2 находились в файле1. Раздел print инструкции оценивает только записи, которые находятся в file2.

FNR и NR часто используются таким образом для СОЕДИНЕНИЯ на основе общности - выбор всех записей из одного набора данных и только связанных записей из другого набора данных. То, что вы реализовали, - это, в частности, «ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ», поскольку оно будет извлекать все записи с «правой» стороны - file2 и соответствующие элементы левой стороны, file1.

Вместо этого вы хотите выполнить «ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ». Все записи в обоих файлах со слиянием записей на основе столбца 1.

FNR == NR означает, что количество записей «FILE» ( FNR ) равно общему количеству Записи ( NR ). NR будет увеличиваться для каждой строки из любого обрабатываемого файла, а FNR сбрасывается в 0 при запуске нового файла. Таким образом, FNR == NR верно только при импорте 2+ файлов при чтении первого файла. Когда awk переключается на следующий файл, FNR сбрасывается на 0, в то время как NR продолжает расти.

Чтобы проиллюстрировать это, я вставил оператор печати, чтобы предоставить состояние этих переменных, когда awk обрабатывает ввод:

$> awk 'FNR==NR{a[$1]=$2;printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]); next}  {printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]$2: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]$2); }' file1 file2

File: file1, NR: 1, FNR: 1, $1: 001, $2: A, a[$1]: A
File: file1, NR: 2, FNR: 2, $1: 002, $2: B, a[$1]: B
File: file1, NR: 3, FNR: 3, $1: 003, $2: C, a[$1]: C
File: file1, NR: 4, FNR: 4, $1: 004, $2: D, a[$1]: D
File: file2, NR: 5, FNR: 1, $1: 002, $2: D, a[$1]$2: BD
File: file2, NR: 6, FNR: 2, $1: 003, $2: D, a[$1]$2: CD
File: file2, NR: 7, FNR: 3, $1: 005, $2: E, a[$1]$2: E
File: file2, NR: 8, FNR: 4, $1: 006, $2: F, a[$1]$2: F

Решение

Чтобы исправить это, все, что вам нужно сделать, это продолжать добавлять записи в массив во время обработки file2, и выводить результаты только после обработки всех входных файлов.

Таким образом, в данном случае нас вообще не интересуют NR или FNR .

  • Для каждой строки текста из всех входных файлов используйте значение первого столбца $ 1 в качестве индекса в массиве a [$ 1]

  • Назначьте значение столбца 2, $ 2 в массив по этому индексу, но добавляем значение, чтобы мы не перезаписывали значение, которое, возможно, уже существует: a [$ 1] = a [$ 1] $ 2

  • Подождите, пока все записи / строк были обработаны перед печатью массива:

    for (i in a) {printf ("% s \ t% s \ n", i, a [i])}

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

$> awk '{ a[$1]=a[$1]$2; next } END { for (i in a) { printf("%s\t%s\n", i, a[i]) } }' file1 file2 | sort -n 

001     A
002     BD
003     CD
004     D
005     E
006     F

Альтернативный подход

Вы также можете использовать команду соединения для этого, но я не знаю, как чтобы заставить его объединить поля - они остаются разделенными пробелами, поэтому требуется дополнительный этап обработки:

$> join  -o 0,1.2,2.2 -a1 -a2 file1 file2 | awk '{printf("%s\t%s%s\n", $1, $2, $3)}'
001     A
002     BD
003     CD
004     D
005     E
006     F

TODO

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

file1: 001 A
и
file2: 001 A
приведет к выходной записи
001 AA

2
27.01.2020, 23:34

Теги

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