Печать столбцов с определенным шаблоном и всеми значениями

У меня есть такой файл:

     OV2  OVI  1VI  OV3  3VI  
er    23   23   23   23   23  
tr    24   24   24   24   24

Я хочу напечатать 1-й столбец вместе со всеми столбцами, имя которых содержит VI (Я заранее не знаю, какие столбцы будут содержать строку. В приведенном выше примере вывод должен быть таким:

     OVI  1VI  3VI  
er    23   23   23     
tr    24   24   24  

все столбцы должны быть разделены табуляцией.

-2
20.05.2017, 15:27
3 ответа
perl -lane '$,="\t";
   $. == 1 and @A = grep $F[$_] =~ /VI/, 0..$#F;
   print @F[0,@A];
' yourfile

Результаты

ID      OVI     1VI     3VI
er      23      23      23
tr      24      24      24

Работа

  • С первой строки, $. == 1 извлечь индексы полей, содержащих строку VI.
  • Вооружившись этим списком индексов в массиве @A, мы просто идем вперед и вырезаем 1-е поле + поля, перечисленные в массиве @A, из Массив @F. Для OFS=$, установлено значение TAB. YMMV.

awk

awk -v OFS="\t" '
   NR==1{
      for ( i=2; i<=NF; i++ )
         if ( $i ~ /VI/ )
            str = str OFS i
      N = split(str, A, OFS)
   }{
      s = $1
      for ( i=2; i<=N; i++ )
         s = s OFS $(A[i])
      $0 = s
   }1
' yourfile

SED

sed -e '
   # TAB->spc, multiple spc -> single spc, trim leading/trailing spc
   y/ / /;s/[ ]\{2,\}/ /g;s/^[ ][ ]*//;s/[ ][ ]*$//

   # only for first line, remove the first field and store remaining in hold area
   1{
      h
         s/[ ]/\
/
         s/.*\n//
      x
   }

   # append hold area (which now has 2nd...last fields
   # data of the first record) to the present line and
   # place a marker at the end of the first field
   G
   s/[^ ][^ ]*[ ]/&\
/

   # setup a do-while loop which progressively either keeps VI data or trims it
   :loop
      #  1     2                      3
      s/\(\n\)\([^ ][^ ]*\)[ ]\{0,1\}\(.*\n\)[^ ]*VI[^ ]*[ ]\{0,1\}/ \2\1\3/;tloop
      s/\(\n\)[^ ][^ ]*[ ]\{0,1\}\(.*\n\)[^ ][^ ]*[ ]\{0,1\}/\1\2/
   /\n\n$/!bloop
   # loop ends when the two \ns collide at the end of line

   # remove the two \ns and what remains is what you wanted
   s///

' yourfile
2
28.01.2020, 05:14

awk решение:

awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
    {if($i~/VI/) a[i]; }}{r=$1; for(i in a) r=r OFS $i; print l}' file

Вывод:

    OVI 1VI 3VI
er  23  23  23
tr  24  24  24

  • FS="[\t ]+" - разделитель полей ввода

  • OFS="\t" - поле вывода разделитель

  • NR==1 - для первой строки header

  • if($i~/VI/) a[i] - номер поля захвата, если он соответствует VI

  • r=1$; for(i in a) r=r OFS $i; print r - итерация по необходимым номерам полей и вывод их соответствующих значений


Если вы столкнулись с нарушением порядка, используйте следующее с функцией asorti() (для сортировки массива по индексам):

awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
    {if($i~/VI/) a[i]; }}{r=$1; asorti(a,b); for(i in b) {r=r OFS $(b[i])} print r}' file
2
28.01.2020, 05:14

Решение скрипта Python. Работает на основе синтаксического анализа первой строки и построения списка столбцов. Для тех столбцов, в которых нет VI, установлено значение None. Все остальные строки разбиваются на слова и объединяются в пары с элементами списка столбцов для сравнения. Если соответствующий элемент столбца равен None, это слово из текущей строки не будет напечатано. В противном случае печатается то, что не None

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as fd:
    indexes = []
    for index,line in enumerate(fd):
        if index == 0:
            columns = line.strip().split()
            for i,col in enumerate(columns):
                if 'VI' in col or i == 0:
                    indexes.append(col)
                else:
                    indexes.append(None)
            for x in indexes:
                if x:
                    print(x,end=" ")
            print("")
            continue
        for j in zip(line.strip().split(),indexes):
            if j[1]:
                print(j[0],end=" ")
        print("")

Примечание: замените end=" " на end="\t" для вывода с разделителями табуляции

Тестовый запуск:

$ ./get_colums.py input.txt                                                                                              
ID  OVI 1VI 3VI 
er  23  23  23  
tr  24  24  24  
1
28.01.2020, 05:14

Теги

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