Поведение awk отличается в моей локальной системе и RedHat 6.5 - PullRequest
0 голосов
/ 17 июня 2020

RHEL 6.5 имеет версию GNU awk, как показано ниже

-bash-4.1$ awk --version
GNU Awk 3.1.7

А в windows 10 я вижу это как -

$ awk --version
GNU Awk 5.0.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.1.2)

Программа AWK использует встроенные переменные awk ARGV и ARGIND. Это что-то связано с системным языком в RHEL?

base.csv:

steve,tignor,ash,michael,jose,sam,joshua
0,0,0,0,0,0,0

file1:

tignor,michael,jose
888,9,-2

file2:

ash,joshua
77,66

merge.awk:

#!/bin/awk
#!/bin/bash

ARGIND==1 && FNR==1{
  split($0, base, ",")
  printf("file,%s\n",$0)
}
ARGIND > 1 && FNR==1{
  split($0, names, ",")
  printf("%s", ARGV[ARGIND])
}
ARGIND > 1 && FNR==2{
  split($0, values, ",")
  for(i in names)
    line[names[i]] = values[i]
  for(i in base){
    if(base[i] in line)
      printf(",%s", line[base[i]])
    else
      printf(",0")
  }
  delete line
  print ""
}

Запуск из Linux приводит к неправильному порядку значений в файле 1 и файле 2

awk -f merge.awk base.csv file*

file,steve,tignor,ash,michael,jose,sam,joshua
file1,9,-2,0,0,0,888,0
file2,0,0,0,66,0,0,77

Но из windows это работает отлично и так, как я хочу.

$ awk -f merge.awk base.csv file1.csv file2.csv
file,steve,tignor,ash,michael,jose,sam,joshua
A1.csv,0,888,0,9,-2,0,0
A2.csv,0,0,77,0,0,0,66

Мы будем благодарны за любые подсказки.

Ответы [ 3 ]

0 голосов
/ 17 июня 2020

@ Shawn Я пробовал использовать обычный массив в стиле c для старого формата стиля GNU-awk.

ARGIND > 1 && FNR==2{
basenum = split($0, base, ",")
  for(i in names)
    line[names[i]] = values[i]
  for (i = 1; i <= basenum; i++) {
    if(base[i] in line)
      printf(",%s", line[base[i]])
    else
      printf(",0")
  }
  delete line

Но результатов не ожидается.

awk -f try.awk base.csv file * file, steve, tignor, a sh, michael, jose, sam, joshua file1,0,0,0 file2,0,0

0 голосов
/ 17 июня 2020

Вот как написать надежный и переносимый код для работы с любым awk в любой среде:

$ cat merge.awk
BEGIN { FS=OFS="," }
NR == FNR {
    if (FNR == 1) {
        numOutFlds = NF
        for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
            names2nrs[$outFldNr] = outFldNr
        }
        print "file", $0
    }
    else {
        split($0,base)
    }
    next
}
{
    if (FNR == 1) {
        delete out2inFldNrs
        for (inFldNr=1; inFldNr<=NF; inFldNr++) {
            outFldNr = names2nrs[$inFldNr]
            out2inFldNrs[outFldNr] = inFldNr
        }
    }
    else {
        printf "%s", FILENAME
        for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
            val = (outFldNr in out2inFldNrs ? $(out2inFldNrs[outFldNr]) : base[outFldNr])
            printf "%s%s", OFS, val
        }
        print ""
    }
}

.

$ awk -f merge.awk base.csv file1 file2
file,steve,tignor,ash,michael,jose,sam,joshua
file1,0,888,0,9,-2,0,0
file2,0,0,77,0,0,0,66
0 голосов
/ 17 июня 2020

awk массивы имеют sh таблицы, и итерация по их элементам с использованием for (x in y) происходит в произвольном порядке. Однако в GNU awk есть способ указать, какой порядок используется, с помощью параметра PROCINFO["sorted_in"] (однако это работает только с GNU awk 4.0 и новее; 3.X не поддерживает его).

Для итерации в порядке возрастания c order:

#!/usr/bin/gawk -f

BEGIN { PROCINFO["sorted_in"] = "@ind_num_asc" }
ARGIND==1 && FNR==1{
  split($0, base, ",")
  printf("file,%s\n",$0)
}
ARGIND > 1 && FNR==1{
  split($0, names, ",")
  printf("%s", ARGV[ARGIND])
}
ARGIND > 1 && FNR==2{
  split($0, values, ",")
  for(i in names)
    line[names[i]] = values[i]
  for(i in base){
    if(base[i] in line)
      printf(",%s", line[base[i]])
    else
      printf(",0")
  }
  delete line
  print ""
}

Вы также можете перебирать элементы по порядку, используя обычный для l oop, и должны делать это в старом версия gawk (включены только соответствующие строки / блоки):

...
basenum = split($0, base, ",")
...
for (i = 1; i <= basenum; i++) {
   if(base[i] in line)
      printf(",%s", line[base[i]])
    else
      printf(",0")
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...