Предложение AWK if для объединения полей

#awk

#awk

Вопрос:

У меня есть файл с разделителями табуляции с > 10 000 строк и переменным количеством столбцов в строке (33-35).

Для строк с 34 столбцами я хотел бы объединить столбцы 3-4 в один:

 col1    col2    col3    col4   ...   col34
index1  tool     kit    math         new
  

чтобы —>

 col1   col2    col3   ...   col33
index1 tool    kit;math     new
  

Аналогично, для 35 столбцов я хотел бы объединить столбцы 3-5 в один. Я предполагаю, что для этого может быть способ использовать AWK и NF. Какие-либо советы или помощь?

Комментарии:

1. Давайте пока забудем о 35 столбцах и создадим простой пример с меньшим количеством столбцов, показывающий, как именно выглядят входные и желаемые выходные данные.

Ответ №1:

В awk:

 NF>5 {                                         # if more than 5 (33) fields
    for(i=(NF-5)-1; i>=0; i--)                 # execute next for once or twice
        for(j=3 i; j<=NF; j  )                 
            $j=( j<4 i ? $j ";" : "" ) $(j 1)  # catenate once or twice on i
    NF=5 
} $1=$1                                        # is this a problem?
  

Запустите его:

 $ awk -v OFS='t' -f program.awk karakfa's.txt
col1    col2    col3    col4    col5
1       2       3;4     5       6
1       2       3       4       5
1       2       3;4;5   6       7
  

Ответ №2:

Вы могли бы сделать это короче, используя цикл for для перебора полей с учетом ваших двух или трех условий, но длинная рука (и более понятная для новичка в awk):

 awk 'NF==35{print $1,$2,$3$4$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35} NF==34{print $1,$2,$3$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34} NF==33{$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33}' yourfile.txt
  

Это полный рот, но это просто распечатка различных комбинаций ваших полей в зависимости от количества полей, присутствующих в записи.

Комментарии:

1. Спасибо! Это очень полезно и имеет смысл. Должен ли я в этом формате предварительно указывать все возможности? Например, исключит ли это строки, где NF < 33? Я хотел бы только специально изменить строки на NF == 34 и NF == 35 и оставить все остальное как есть.

2. Это исключило бы записи, длина которых не составляла 33, 34 или 35 полей. Вы можете изменить это последнее условие на NF<=33 или NF!=34 amp;amp; NF!=35 или NF<34 || NF>35 или что угодно.

Ответ №3:

вот еще awk один вариант с большей гибкостью. Вместо этого я использовал 5-7 столбцов.

 $ cat file
col1    col2    col3    col4    col5
1       2       3       4       5       6
1       2       3       4       5
1       2       3       4       5       6       7

$ awk -v OFS='t' 'NR==1{print; next} 
                    NF>5{$3=$3 $4; t=1} 
                    NF>6{$3=$3 $5; t=2} 
                       t{for(i=4;i<=NF;i  ) $i=$(i t);
                         NF=NF-t; t=0}1' file

col1    col2    col3    col4    col5
1       2       34      5       6
1       2       3       4       5
1       2       345     6       7
  

Ответ №4:

TXR-реализация парадигмы awk примерно в 270 строках TXR Lisp:

Разминка: объединение базовых столбцов по всему файлу:

 $ txr -e '(awk ((>= nf 4) (set [f 2..4] (list `@[f 2];@[f 3]`)))
               (t))'
1
1
1 2
1 2
1 2 3
1 2 3
1 2 3 4
1 2 3;4
1 2 3 4 5
1 2 3;4 5
  

Поля представляют собой список f , а не специальный синтаксический гаджет, включающий знаки доллара, поэтому они подвержены назначению фрагмента: (set [target-sequence n..m] source-sequence) заменяет n..m фрагмент (от n до m , исключая m ) target-sequence на source-sequence . Индексация начинается с нуля, поэтому для замены третьего и четвертого полей мы обозначаем срез 2..4 : т. е. индексы 2 и 3, не включая 4.

Это (t) предложение условия-действия без условий, аналогичное Awk 1 : оно запускает неявную (prn) форму, которая выводит rec (эквивалент $0 ); t это самооценочный символ, который канонически обозначает логическое значение true, хотя любое значение, отличное от nil true . Когда f обрабатывается определенным образом, например, с помощью приведенного выше назначения фрагмента, rec автоматически воссоздается из полей путем вставки ofs между ними, точно так же, как перемещение полей в Awk Classic $0 reconstitutions .

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

 $ txr -e '(awk ((= nr 1) (prn) (next))
               ((>= nf 4) (set [f 2..4] (list `@[f 2];@[f 3]`)))
               (t))'
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 3 3;4 5
  

Далее у нас есть требование об изменении диапазона для 34 против 35. Как насчет того, чтобы использовать условие «34 или более столбцов». Диапазон сдвига может быть обработан путем изменения выражения:

 [f 2..4]
  

Для

 [f (if (> nf 34) 2..5 2..4))]
  

но мы можем сделать это унифицированным способом, если мы привяжем условный диапазон к переменной, а затем используем его в нескольких местах. Нам нужно только один раз проверить условие. Результатом является:

 $ txr -e '(awk ((= nr 1) (prn) (next))
               ((>= nf 4) (let ((r (if (> nf 34) 2..5 2..4)))
                            (set [f r] (list `@{[f r] ";"}`))))
               (t))'
col1 col2 ...
col1 col2 ...
1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y
1 2 3;4;5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y
1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X
1 2 3;4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X
  

Внутри квазистрочного литерала, разделенного обратным символом, синтаксис @{[seq range] string} будет интерполировать фрагмент последовательности, используя строку в качестве разделителя. Мы просто интерполируем диапазон r , который является тем же диапазоном, который мы удаляем и заменяем результирующей строкой; мы переключаемся r условно на то, есть ли у нас более 34 столбцов, поэтому тест выполняется только в одном месте и r используется в двух местах.

Комментарии:

1. Искренне благодарен за объяснение и помощь!!