замена определенного столбца определенным значением с помощью gawk

Я пытаюсь найти везде, где мои данные имеют 90 в столбце 2, а две строки выше изменяют значение столбца 2. Например, в моих данных ниже, если я вижу 90 в строке 11, я хочу изменить значение столбца 2 в строке 9 от 11 до 5. У меня есть заранее определенный набор значений, на который я хочу изменить число; значения всегда будут от 10,11,12,30,31,32 до 1,2,3,4,5,6 соответственно.

Мои данные

 #      Type    Response        Acc     RT      Offset    
   1      70  0    0   0.0000 57850
   2      31  0    0   0.0000 59371
   3      41  0    0   0.0000 60909
   4      70  0    0   0.0000 61478
   5      31  0    0   0.0000 62999 
   6      41  0    0   0.0000 64537
   8      70  0    0   0.0000 65106
   9      11  0    0   0.0000 66627
  10      21  0    0   0.0000 68165
  11      90  0    0   0.0000 68700
  12      31  0    0   0.0000 70221

Что я хочу

 #      Type    Response        Acc     RT      Offset    
   1      70  0    0   0.0000 57850
   2      31  0    0   0.0000 59371
   3      41  0    0   0.0000 60909
   4      70  0    0   0.0000 61478
   5      31  0    0   0.0000 62999 
   6      41  0    0   0.0000 64537
   8      70  0    0   0.0000 65106
   9       5  0    0   0.0000 66627
  10      21  0    0   0.0000 68165
  11      90  0    0   0.0000 68700
  12      31  0    0   0.0000 70221

Я пытался сохранить предыдущую строку и использовать ее в качестве ссылки, но я могу вернуться только на одну строку, а мне нужно вернуться на две. Спасибо за помощь.


person user1269741    schedule 18.03.2012    source источник
comment
Ваши последовательности перевода с 10,11,12,30,31,32 на 1,2,3,4,5,6 не совпадают с вашим требованием изменить 11 на 5   -  person Peter.O    schedule 18.03.2012


Ответы (2)


Это должно работать:

function pra(a) {
  for(e in a) {
    printf "%s ", a[e];
  }
  print ""; 
}
BEGIN {
  vals[10] = 1;
  vals[11] = 2;
  vals[12] = 3;
  vals[30] = 4;
  vals[31] = 5;
  vals[32] = 6;
}
NR == 1 { split($0, a, " ") }
NR == 2 { split($0, b, " ") }
NR > 2 { 
  if($2 == "90") {
    a[2] = vals[a[2]];
  }
  pra(a);
  al = 0;
  for(i in a) al++;
  for(i = 1; i <= al; i++) {
    a[i] = b[i];
  }
  split($0, b, " ");
}
END {
  pra(a);
  pra(b);
}

Краткое описание того, как это работает: * Блок BEGING — присвойте значения перевода vals * NR == 1 и NR == 2 — запомните первые две строки в разделенных массивах a и b * NR > 2 — для всех строк после первой two * Если второй столбец имеет значение 90, измените его с помощью массива перевода * Переместите элементы массива b в a и разбейте текущую строку на b * Блок END - напечатайте a и b, которые в основном являются двумя последними строками

Пример запуска:

$ cat inp && awk -f mkt.awk inp 
 #      Type    Response        Acc     RT      Offset    
   1      70  0    0   0.0000 57850
   2      31  0    0   0.0000 59371
   3      41  0    0   0.0000 60909
   4      70  0    0   0.0000 61478
   5      31  0    0   0.0000 62999 
   6      41  0    0   0.0000 64537
   8      70  0    0   0.0000 65106
   9      11  0    0   0.0000 66627
  10      21  0    0   0.0000 68165
  11      90  0    0   0.0000 68700
  12      31  0    0   0.0000 70221

# Type Response Acc RT Offset 
1 70 0 0 0.0000 57850 
2 31 0 0 0.0000 59371 
3 41 0 0 0.0000 60909 
4 70 0 0 0.0000 61478 
5 31 0 0 0.0000 62999 
6 41 0 0 0.0000 64537 
8 70 0 0 0.0000 65106 
9 2 0 0 0.0000 66627 
10 21 0 0 0.0000 68165 
11 90 0 0 0.0000 68700 
12 31 0 0 0.0000 70221 

Вы можете сделать что-то вроде этого:

function pra(a) {
  printf "%4d%8d%3d%5d%9.4f%6d\n", a[1], a[2], a[3], a[4], a[5], a[6]
}
BEGIN {
  vals[10] = 1;
  vals[11] = 2;
  vals[12] = 3;
  vals[30] = 4;
  vals[31] = 5;
  vals[32] = 6;
}
NR == 1 { print }
NR == 2 { split($0, a, " ") }
NR == 3 { split($0, b, " ") }
NR > 4 {
  if($2 == "90") {
    a[2] = vals[a[2]];
  }
  pra(a);
  for(i = 1; i <= 6; i++) {
    a[i] = b[i];
  }
  split($0, b, " ");
}
END {
  pra(a);
  pra(b);
}

Чтобы заставить его работать для этого конкретного случая, который включает форматирование. Пример запуска:

$ cat inp && awk -f mkt.awk inp 
 #      Type    Response        Acc     RT      Offset    
   1      70  0    0   0.0000 57850
   2      31  0    0   0.0000 59371
   3      41  0    0   0.0000 60909
   4      70  0    0   0.0000 61478
   5      31  0    0   0.0000 62999 
   6      41  0    0   0.0000 64537
   8      70  0    0   0.0000 65106
   9      11  0    0   0.0000 66627
  10      21  0    0   0.0000 68165
  11      90  0    0   0.0000 68700
  12      31  0    0   0.0000 70221 
 #      Type    Response        Acc     RT      Offset    
   1      70  0    0   0.0000 57850
   2      31  0    0   0.0000 59371
   4      70  0    0   0.0000 61478
   5      31  0    0   0.0000 62999
   6      41  0    0   0.0000 64537
   8      70  0    0   0.0000 65106
   9       2  0    0   0.0000 66627
  10      21  0    0   0.0000 68165
  11      90  0    0   0.0000 68700
  12      31  0    0   0.0000 70221
person icyrock.com    schedule 18.03.2012
comment
Вау, спасибо, что так быстро ответили. Я попробовал ваш код, возможно ли сохранить форматирование данных, как показано выше? Когда я запустил ваш код, он выдал мне вывод с измененными данными и заголовком (Acc RT Offset # Type Response 0 0,0000 43991 1 55 0). Кроме того, можно ли дать мне разбивку того, как работает код? Кроме того, большое спасибо, это действительно работало по большей части. - person user1269741; 18.03.2012
comment
Спасибо - посмотрите редактирование, надеюсь, это даст вам что-то, над чем можно поработать. - person icyrock.com; 18.03.2012
comment
Примечание. Плохая замена, когда рассматриваемое поле нет в списке 10,11,12,30,31,32 ... Он заменяет любое число, которое там было, на 0 ... Он упоминает, что данный список имеет определенные замены, но Я не уверен, имеет ли он в виду, что список содержит единственно возможные значения... (Стоит упомянуть, могут ли быть другие значения). - person Peter.O; 18.03.2012
comment
Большое спасибо, второй код работает, позволяя мне сохранить форматирование. Все мои значения 10,11,12,30,31,32, поэтому в этой части нет проблем, но спасибо за ваши опасения, и я буду следить за ними в будущем. Также спасибо за разбор, который был очень полезным. - person user1269741; 18.03.2012

Эта версия поддерживает исходное форматирование

awk 'BEGIN{ new[" 1"]="10"; new[" 2"]="11"; new[" 3"]="12"
            new[" 4"]="30"; new[" 5"]="31"; new[" 6"]="32" }
     { line[-2]=line[-1]; line[-1]=line[0]; line[0]=$0 } 
     $2==90 { if( match( line[-2], /^ *[0-9]+ +[1-6] / ) ) { 
                  old=substr( line[-2], RLENGTH-2,2 )
                  line[-2]=substr( line[-2], 1, RLENGTH-3 ) new[old] \
                           substr( line[-2], RLENGTH ) } }
     NR>2 { printf("%s\n",line[-2]) } 
     END { printf("%s\n%s\n",line[-1],line[0]) }' file.in
person Peter.O    schedule 18.03.2012