Как я могу изменить порядок строк на основе шаблона? - PullRequest
0 голосов
/ 15 января 2020

У меня есть файлы с данными, но некоторые строки содержат данные в неправильном порядке:

name cat
value 7.25 label X
value 1.13 label 2
value 15.75 label 1  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
name cow
value 1.10 label 2
value 8.25 label X
value 19.00 label 1  
name sheep
value 1.11 label 2
value 8.80 label X
value 19.00 label 1  
name mouse
value 1.13 label 2
value 8.00 label X
value 19.00 label 1  
name donkey
value 1.05 label 2
value 9.50 label X
value 16.00 label 1  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  

Как видите, некоторые строки начинаются с метки *, а некоторые строки начинаются со значения *, я буду sh чтобы поменять местами порядок строк, когда строка начинается со значения 'value', поэтому все строки (игнорируя строку, содержащую имя) имеют следующий формат: 'Label * value *'

Желаемый результат:

name cat
label X value 7.25
label 2 value 1.13
label 1 value 15.75  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
name cow
label 2 value 1.10
label X value 8.25
label 1 value 19.00 
name sheep
label 2 value 1.11
label X value 8.80
label 1 value 19.00  
name mouse
label 2 value 1.13
label X value 8.00
label 1 value 19.00  
name donkey
label 2 value 1.05
label X value 9.50
label 1 value 16.00  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  

Я пытался написать al oop, опуская строки, начинающиеся со значения 'value', однако я не уверен в следующих шагах.

Как я могу добиться этого?

Ответы [ 4 ]

4 голосов
/ 15 января 2020

Это задание идеально подходит для awk:

awk '$1 == "value" { print $3, $4, $1, $2; next; } 1'

awk программ, состоящих из пар условие / работа; код внутри первого блока выполняется только в том случае, если $1 == "value" истинно, в этом случае операции отменяются; 1 - пустое условие (которое, таким образом, получает заданную по умолчанию операцию печати всей строки, которая выполняется всякий раз, когда первое условие не выполнялось (с помощью команды next, заставляющей управление потоком переходить непосредственно к следующей строке ввода) .

2 голосов
/ 15 января 2020

Ответ Чарльза хорош для этой проблемы, но нужно еще кое-что рассмотреть, если у вас есть пары тег-значение в других, более сложных контекстах, - сначала создать массив этих пар, а затем распечатать их так, как вам нравится по их тегам / именам. :

$ awk '
    function p(tag) { return (tag OFS f[tag]) }
    NF==4 { for (i=1;i<NF;i+=2) f[$i]=$(i+1); $0=p("label") OFS p("value") }
1' file
name cat
label X value 7.25
label 2 value 1.13
label 1 value 15.75
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10
name cow
label 2 value 1.10
label X value 8.25
label 1 value 19.00
name sheep
label 2 value 1.11
label X value 8.80
label 1 value 19.00
name mouse
label 2 value 1.13
label X value 8.00
label 1 value 19.00
name donkey
label 2 value 1.05
label X value 9.50
label 1 value 16.00
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10
2 голосов
/ 15 января 2020

как то так:

sed 's/^\(label .* \)\(value .*\)/\2 \1/'
0 голосов
/ 15 января 2020

Это решение требует gawk (gnu awk) вместо традиционного awk. Вот оно:

BEGIN {
        IGNORECASE = 1;
    }
    {
        if( match( $0, \
          /value[[:space:]]+([0-9\.]+)[[:space:]]+label[[:space:]]+([0-9A-Z]+)/,
          groups ) )
          printf( "label %s value %s\n", groups[2], groups[1]);
        else
          print $0;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...