#unix #awk #filtering
#unix #awk #фильтрация
Вопрос:
Я пытаюсь отфильтровать файл, выбрав первую и последнюю строки заданной переменной в текстовом файле с разделителями табуляции, используя AWK.
Файл с разделителями табуляции выглядит следующим образом:
1 apple 30
2 apple 35
3 apple 36
4 apple 20
5 pear 10
6 pear 30
7 pear 45
8 orange 16
END
и я пытаюсь обработать это с помощью awk, чтобы печатать только первую и последнюю строки каждой переменной в $ 2 (столбец fruit в этом примере)
Файл, который у меня на самом деле есть, имеет длину ~ 35000 строк и содержит 3000 уникальных переменных в столбце, который я хочу использовать в качестве фильтра (так, в приведенном выше примере col2)
Я думал, что подход будет заключаться в создании массива уникальных значений col2 (яблоко, груша, апельсин), а затем, используя этот массив, извлекает первое и последнее значения из файла большего размера… но некоторые рекомендации по номенклатуре, необходимой для выбора первой и последней строки для каждой индексированной переменной, были бы весьма признательны. 🙂
ВХОДНОЙ файл, указанный выше, ожидаемый результат будет
1 apple 30
4 apple 20
5 pear 10
7 pear 45
8 orange 16
выходные данные также должны включать те, у которых есть только одна запись (в данном случае оранжевая)
Комментарии:
1. Отсортирован ли файл по столбцу 2?
2. Привет, да, файл отсортирован по столбцу 2.
Ответ №1:
Один из способов:
awk '$2!=prev{if (pline){print pline;}print;}{prev=$2;pline=$0;}END{print pline;}' file | uniq
Печатайте каждый раз, когда встречается новая строка 2-го столбца. При печати новой строки 2-го столбца, если предыдущая строка не пуста, распечатайте и ее. uniq заключается в удалении повторяющихся строк, которые печатаются в случае наличия единственной записи между ними.
Ответ №2:
Это будет работать, даже если одни и те же данные отображаются как в первой, так и в последней строке для заданного значения ключа или если данные содержат пустые или 0
строки (при условии, что вы хотите, чтобы они обрабатывались так же, как и любая другая строка, легко пропускаются, если нет):
$ cat tst.awk
$2 != prev2 {
if ( NR > 1 ) {
print rec
}
beg = rec = $0
prev2 = $2
next
}
{ rec = beg ORS $0 }
END { print rec }
$ awk -f tst.awk file
1 apple 30
4 apple 20
5 pear 10
7 pear 45
8 orange 16
Ответ №3:
пробовал на gnu awk, внешняя программа не нужна
awk '{if($0~/^[a-z0-9]/) a[NR]=$0} END{f=1;asort(a); for(;i <NR;){split(a[i],b);if(b[2]==$2||f){$1=b[1];$2=b[2];$3=b[3];if(f){f=0;print}} else if(b[2]){print;print b[1],($2=b[2]),b[3]}} }' d