Вставьте файлы с неравными строками и несколькими столбцами в Unix - PullRequest
0 голосов
/ 31 октября 2019

Допустим, у меня есть три файла со следующим содержанием:

file1:

AAA     BBB     CCC
123     563     2467

file2:

NA      NA      NA

file3:

DDD     EEE     FFF
2333    236     908
123     376     887

Я хочу вставить эти файлы и вставить 0 для пустых полей, как показано ниже:

AAA     BBB     CCC     NA      NA      NA      DDD     EEE     FFF
123     563     2467    0       0       0       2333    236     908
0       0       0       0       0       0       123     376     887

Я даже не смог пройти первый шаг для вставки. когда я попробовал paste file1 file2 file3, это выглядит так:

AAA BBB CCC NA  NA  NA  DDD EEE FFF
123 563 2467        2333    236 908
        123 376 887

Хотя я обнаружил, что pr -m -t file1 file2 file3 работает, но он не отображает полные строки, так как у меня есть несколько длинных строк.

Как мнезаставить это работать в этом случае? Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 31 октября 2019

Не могли бы вы попробовать следующее. Это выглядит более надежно, вот его преимущества:

  • Он должен работать и без GNU awk (хотя я не смог протестировать все его версии).
  • Он будет искать максимальное количество строк во всех переданных файлах Input_file и будет печатать нули в соответствии с максимальным количеством полей в этой нулевой строке.
  • Он также будет выглядеть, если строка (2-я строка в 1-м Input_file и 2-й строке)во втором Input_file), и если они имеют меньшее количество полей, он также добавит к строке оставшиеся числовые поля (просто добавьте).

awk '
FNR==1{
  total_fields=total_fields>NF?total_fields:NF
  ++file
}
{
  file_lines[file]++
  a[FNR,file]=$0
}
END{
  for(i in file_lines){
     val=val>file_lines[i]?val:file_lines[i]
  }
  for(i=1;i<=val;i++){
     for(j=1;j<=file;j++){
       num=split(a[i,j],array," ")
       if(num<total_fields){
          new_val=sprintf("%0"total_fields-num"d","")
          ##printf "....... "total_fields-num">>>>"new_val" "
          gsub(/0/,"0 ",new_val)
          a[i,j]=(a[i,j]?a[i,j] OFS:"")new_val
          new_val=""
       }
       if(!a[i,j]){
          a[i,j]=sprintf("%0"total_fields"d",a[i,j])
          gsub(/0/,"0 ",a[i,j])
       }
       printf("%s%s",a[i,j],j==file?ORS:OFS)
       new_val=""
     }
  }
}
'   file1  file2  file3  |  column -t
1 голос
/ 31 октября 2019

Вы можете использовать GNU awk для него (изменено с этот ответ . Обратите внимание на часть заказа):

$ gawk '
BEGIN {
    FS=OFS="\t"                                                   # set delimiters
}
{
    for(i=1;i<=NF;i++)                                            # iterate data fields
        a[FNR][s+i]=$i                                            # hash them
}
ENDFILE {
    s+=NF                                                         # store field count
}
END {
    for(i in a) {                                                 # in awk order
        for(j=1;j<=s;j++)                                         # and data
            printf "%s%s",(a[i][j]==""?0:a[i][j]),(j==s?ORS:OFS)  # output
    }
}' file1 file2 file3

Вывод:

AAA     BBB     CCC     NA      NA      NA      DDD     EEE     FFF
123     563     2467    0       0       0       2333    236     908
0       0       0       0       0       0       123     376     887
0 голосов
/ 31 октября 2019

здесь есть другой подход

$ paste -d~ file1 file2 file3 | 
  awk -F~ '{$1=$1; for(i=1;i<=NF;i++) if($i=="") $i=nvl[i]}1
     NR==1 {for(i=1;i<=NF;i++) {gsub(/[^ ]+/,0,$i); nvl[i]=$i}}' | column -t


AAA  BBB  CCC   NA  NA  NA  DDD   EEE  FFF
123  563  2467  0   0   0   2333  236  908
0    0    0     0   0   0   123   376  887

для команды pr. Вы можете отключить усечение с помощью опции -J, которая будет работать для длинных строк, но без подстановки пропущенных значений.

$ pr -Jmt file{1..3}
...