Извлечение данных с помощью awk, когда некоторые строки имеют пустые/пропущенные значения

В bash есть три варианта: echo -e , printf и $ '. .. '.

Последний из них самый простой:

$ name="Hello"; name=$name$'\033[34m(Test)\e[0m' ; echo "$name"
Hello(Test)

В этом случае цветовой код был сохранен в переменной. Самый простой способ «увидеть» коды (помимо просмотра цвета) - использовать некоторую шестнадцатеричную программу просмотра:

$ echo "$name" | od -vAn -tcx1
   H   e   l   l   o 033   [   3   5   m   (   T   e   s   t   )
  48  65  6c  6c  6f  1b  5b  33  35  6d  28  54  65  73  74  29
 033   [   0   m  \n
  1b  5b  30  6d  0a

Используйте ее, когда вам нужно «увидеть» коды (и почему они работают или не работают).

Цветовые коды уже интерпретированы внутри переменной. Таким образом вы можете создать переменную для некоторого цвета и использовать ее:

$ blue=$'\033[34m'; reset=$'\033[0m'
$ echo "Hello $blue Test $reset Colors"

Другой способ - хранить коды внутри переменной и интерпретировать их каждый раз, когда потребуется их «эффект».

$ blue='\033[34m'; reset='\033[0m'
$ echo "Hello $blue Test $reset Colors"
Hello \033[34m Test \033[0m Colors
$ echo -e "Hello $blue Test $reset Colors"
Hello  Test  Colors

«Тест» - синий, а «Цвета» - черный (если экран вашей консоли белый).

Команда echo -e не такая переносимая (и безопасная), как printf:

$ blue='\033[34m'; reset='\033[0m'
$ printf "%s $blue%s $reset%s" "Hello" "Test" "Colors"
Hello Test Colors

Весь список цветов (фон) будет виден с (печатью пробела):

 printf '\e[%sm ' {40..47} 0; echo

Или , с цветами переднего плана:

 printf '\e[%smColor=%s  ' {30..37}{,} 0 0; echo
5
07.11.2016, 14:45
3 ответа

Вы можете получить почти , используя утилиту Unpand , чтобы «табулировать» ввод, а затем установить awk разделитель полей для табуляции и печати только строк, последнее поле которых состоит из чего-то другого, кроме пробелов:

unexpand -t8 input.txt | awk -F'\t' '$NF ~ /[^ ]/ {print $1, $NF}'
    usr1   B
    usr2   C
    usr4   A
    usr6   A

Это не работает для строки заголовка, потому что между позициями меньше пробелов и ref поля. Если заголовок необходим, вы можете обработать его отдельно:

unexpand -t8 input.txt | awk -F'\t' 'NR == 1 {print $1,$3} $NF ~ /[^ ]/ {print $1, $NF}'
1
27.01.2020, 20:31

Команда awk - не самый подходящий инструмент для этой работы. Используйте команду cut, которая принимает в качестве аргумента символьные позиции полей, которые вы хотите извлечь. Поэтому в вашем примере укажите, что USERS начинается с позиции 1 и заканчивается позицией 8, а rslt начинается с позиции 33.

$ cut -c 1-8,33- input.txt
   USERS rslt
    usr1  B
    usr2  C
    usr3
    usr4  A
    usr5
    usr6  A
    usr7

О том, как считать позиции символов, см. следующее.

         1         2         3         
123456789012345678901234567890123456789
   USERS        position   ref   rslt   
    usr1                    X     B   
    usr2          2980            C   
    usr3          3323      P      
    usr4                          A  
    usr5          5251      U      
    usr6          9990            A
    usr7          10345     T      
6
27.01.2020, 20:31

В этом случае одним из возможных решений является чтобы указать ширину полей в начальном разделе:

awk 'BEGIN {FIELDWIDTHS = "16 11 6 7"} 
    $4 ~/[^ ]/ {print $1 $4}' 

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

 head -1 f | grep -Po '.*? (?=\S|$)' | awk '{print length}'

ОБНОВЛЕНИЕ: ... или чтобы иметь дело с начальные и конечные пробелы в заголовке:

 head -1 f | grep -Po '(^ *|\S).*?( (?=\S)|$)' | awk '{print length}'
12
27.01.2020, 20:31

Теги

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