Обработка 3 файлов с использованием awk

9

Рассмотрим следующие файлы:

file1:

boo,8,1024
foo,7,2048

file2:

foo,0,24,154
noo,0,10,561

file3:

24,154,7,1024,0

Что мне нужно, это пойти в File1 и проверить, если $2==7; если это правда, взять $1, $2и $3от File1 ; Теперь я должен сравнить, если $1из File1 равно $1из File2 ; если это правда, я должен взять $3и $4из Файл2 , которые не существуют в File1 , то я должен пойти file3 и проверить , если $1от file3 равно $3от Файл2 , и $2от file3 равно $4от Файл2 ; если да, то я должен проверить, если $2из File1равно $3из File3 , то, если это условие истинно, я должен сравнить $3с File1 с $4из File3 , если $3из File1 больше, чем $4из File3 .

Я попробовал следующий скрипт:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

Желаемый результат:

foo,7,2048,24,154,1024
Eng7
источник

Ответы:

9

Это сработало для меня:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

Пояснение :

  • Первая строка ( FNR==1{++f}) увеличивает индекс файла, чтобы позже определить, в каком файле мы 1-3.
  • file1: если $2равно7
    • заполнить массив a1с $1как индекс , и a2с $2как индекс , и в $3качестве значения
    • запишите oпеременную (выходную) с первыми 3 полями
  • file2: если $1из file2равных $1по file1(написано в Данные о предыдущих a1)
    • добавить $3и $4к выходной переменной o.
    • заполнить массив a3с $3как индекс , и в $4качестве значения.
  • файл3: если:
    • $1равно file2s $3(индекс a3)
    • $2равно file2s $4(значение a3)
    • $3равно file1s $2(индекс a2)
    • $4ниже, чем file1s $3(значение a2)
  • тогда:
    • выведите значение o.
хаос
источник
Есть ли необходимость в обратном слэше (кроме последнего)? как насчет BEGINFILE (вместо FNR == 1)?
Архемар
@Archemar BEGINFILE и ENDFILE являются расширениями gawk, и все обратные слеши могут быть удалены, я вставил их, для лучшей читабельности: вы можете написать все это в одну строку, но это не выглядело бы хорошо
хаос
@chaos, спасибо, но, к сожалению, всегда возвращает ноль.
Eng7
@ Azizieh7 Я протестировал его с mawk и gawk с вашими 3 входными примерами файлов. Для меня это сработало. Используете ли вы разные входные файлы или кодировки / переносы строк?
хаос
@chaos, в file3 есть различные разрывы строк, но я использую tr -d '\ 015' для преодоления этого.
Eng7
1

Решение TXR:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

Запустить:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

Но проницательный наблюдатель заметит, что цифра 7 не указана нигде в коде, а только в выводе! Это потому, что код на самом деле проходит через все записи file1и печатает все комбинации, которые соответствуют совпадениям и ограничениям . Единственный в данных образца - это тот, кто val0был 7.

Если бы было найдено больше комбинаций, это можно было бы ограничить только 7такой:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

Язык извлечения шаблонов TXR обеспечивает здесь одно большое сопоставление шаблонов с неявными обратными ссылками посредством повторения имен переменных, охватывающих несколько файлов, с многострочными шаблонами извлечения и нетекстовыми ограничениями, плюс встроенные побочные эффекты, такие как вывод и т. Д. ,

Принятое решение Awk тщательно перевело awkмакрос TXR Lisp :

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

Запустить:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

,1024Требуется часть на выходе отсутствует; оригинальный "Awk Classic" имеет такое поведение.

Kaz
источник