Манипулирование колонкой с использованием Bash & Awk - PullRequest
2 голосов
/ 08 апреля 2020

Предположим, у нас есть файл example1.txt, состоящий из нескольких строк.

item item item  
 A    B    C      
100  20   2       
100  22   3
100  23   4
101  26   2
102  28   2
103  29   3
103  30   2
103  32   2
104  33   2
104  34   2
104  35   2
104  36   3

Есть несколько команд, которые я хотел бы выполнить, чтобы отфильтровать текстовые файлы и добавить еще несколько столбцов.

Сначала я хочу применить условие, когда элемент C равен 2. Используя команду awk, я могу сделать это следующим образом.

Поэтому текстовый файл возврата будет:

awk '$3 == 2 { print $1 "\t"  $2  "\t" $3} ' example1.txt > example2.txt

item item item
 A    B    C      
100  20   2       
101  26   2
102  28   2
103  30   2
103  32   2
104  33   2
104  34   2
104  35   2

Теперь я хочу посчитать две вещи:

Я хочу посчитать общее уникальное число в столбце 1.

For example, in the above case example2.txt, it would be:
(100,101,102,103,104) = 5

И я хотел бы добавить повторяющийся номер столбца A и добавить его в новый столбец.

Я хотел бы иметь следующее:

item item item  item
 A    B    C     D
100  20   2      1
101  26   2      1
102  28   2      1
103  30   2      2
103  32   2      2
104  33   2      3
104  34   2      3
104  35   2      3

~

Над столбцом Элемент D (4-й) 1-й ряд равен 1, потому что в нем не было повторений. но в 4-м ряду это 2, потому что 103 повторяется дважды. Поэтому я добавил 2 в 4-м и 5-м столбцах. Аналогично, последние три столбца в элементе 4 равны 3, поскольку элемент A повторяется три раза в этих трех столбцах.

Ответы [ 4 ]

3 голосов
/ 08 апреля 2020

Вы можете попробовать это awk:

awk -v OFS='\t' 'NR <= 2 {
   print $0, (NR == 1 ? "item" : "D")
}
FNR == NR && $3 == 2 {
   ++freq[$1]
   next
}
$3 == 2 {
   print $0, freq[$1]
}' file{,}

item  item  item  item
A     B     C     D
100   20    2     1
101   26    2     1
102   28    2     1
103   30    2     2
103   32    2     2
104   33    2     3
104   34    2     3
104   35    2     3
3 голосов
/ 08 апреля 2020

Не могли бы вы попробовать следующее. Если вы хотите сохранить вывод в тот же файл Input_file, добавьте > temp && mv temp Input_file к следующему коду.

awk '
FNR==NR{
  if($3==2){
    a[$1,$3]++
  }
  next
}
FNR==1{
  $(NF+1)="item"
  print
  next
}
FNR==2{
  $(NF+1)="D"
  print
  next
}
$3!=2{
  next
}
FNR>2{
  $(NF+1)=a[$1,$3]
}
1
' Input_file  Input_file | column -t

Вывод будет следующим:

item  item  item  item
A     B     C     D
100   20    2     1
101   26    2     1
102   28    2     1
103   30    2     2
103   32    2     2
104   33    2     3
104   34    2     3
104   35    2     3


Объяснение: Добавление подробного объяснения для вышеуказанного кода.

awk '                    ##Starting awk program fro here.
FNR==NR{                 ##Checking condition if FNR==NR which will  be TRUE when 1st time Input_file is being read.
  if($3==2){             ##Checking condition if 3rd field is 2 then do following.
    a[$1,$3]++           ##Creating an array a whose index is $1,$3 and keep adding its index with 1 here.
  }
  next                   ##next will skip further statements from here.
}
FNR==1{                  ##Checking condition if this is first line.
  $(NF+1)="item"         ##Adding a new field with string item in it.
  print                  ##Printing 1st line here.
  next                   ##next will skip further statements from here.
}
FNR==2{                  ##Checking condition if this is second line.
  $(NF+1)="D"            ##Adding a new field with string item in it.
  print                  ##Printing 1st line here.
  next                   ##next will skip further statements from here.
}
$3!=2{                   ##Checking condition if 3rd field is NOT equal to 2 then do following.
  next                   ##next will skip further statements from here.
}
FNR>2{                   ##Checking condition if line is greater than 2 then do following.
  $(NF+1)=a[$1,$3]       ##Creating new field with value of array a with index of $1,$3 here.
}
1                        ##1 will print edited/non-edited lines here.
' Input_file Input_file   ##Mentioning Input_file names 2 times here.
2 голосов
/ 08 апреля 2020

Аналогично другим, но с использованием awk с однократным проходом и сохранением информации в массивах относительно записей seen и подсчета для D с массивами ord и Dcnt, использованными для отображения информация для каждого, например,

awk '
    FNR == 1 { h1=$0"\titem" }      # header 1 with extra "\titem"
    FNR == 2 { h2=$0"\tD" }         # header 2 with exter "\tD"
    FNR > 2 && $3 == 2 {            # remaining rows with $3 == 2
        D[$1]++                     # for D colum times A seen
        seen[$1,$2] = $0            # save records seen
        ord[++n] = $1 SUBSEP $2     # save order all records appear
        Dcnt[n] = $1                # save order mapped to $1 for D
    }
END {
    printf "%s\n%s\n", h1, h2       # output headers
    for (i=1; i<=n; i++)            # loop outputing info with D column added
        print seen[ord[i]]"\t"D[Dcnt[i]]
    }
' example.txt

( примечание: SUBSEP - это встроенная переменная, которая соответствует разделителю подстроки, используемому при использовании запятой для объединения полей для массива индекс, например, seen[$1,$2], чтобы разрешить сравнение вне массива. Это по умолчанию "\034")

Пример вывода

item item item  item
A    B    C    D
100  20   2     1
101  26   2     1
102  28   2     1
103  30   2     2
103  32   2     2
104  33   2     3
104  34   2     3
104  35   2     3

Всегда более чем в одну сторону до кожа кота с awk.

0 голосов
/ 08 апреля 2020

Предполагается, что файл не большой;

awk 'NR==FNR && $3 == 2{a[$1]++;next}$3==2{$4=a[$1];print;}' file.txt file.txt

Вы анализируете файл дважды. На первой итерации вы вычисляете 4-й столбец и получаете его в массиве. Во втором разборе мы устанавливаем счет как 4-й столбец и печатаем всю строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...