Регулярное выражение ^[[:digit:]]$ не работает должным образом в AWK/GAWK

Моя версия GAWK на RHEL:

gawk-3.1.5-15.el5

Я хотел напечатать строку, если в первом ее поле есть все цифры (без специальных символов, даже с учетом пробела)

Example:

echo "123456789012345,3" | awk -F, '{if ($1 ~ /^[[:digit:]]$/)  print $0}'

Output:
Nothing

Expected Output:
123456789012345,3

Что здесь происходит не так? Моя версия AWK не понимает классы символов GNU? Пожалуйста, помогите


person dig_123    schedule 23.12.2016    source источник


Ответы (3)


Чтобы сопоставить несколько цифр в классе символов [[:digit:]], добавьте +, что означает соответствие одной или нескольким цифрам в $1.

echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]+)$/)  print $0}'
123456789012345,3

который удовлетворяет вашим требованиям.

Более идиоматический способ (как предлагается из комментариев) состоял бы в том, чтобы отбросить print и включить прямое совпадение в строку и напечатать его,

echo "123456789012345,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'
123456789012345,3

Еще несколько примеров, демонстрирующих то же самое,

echo "a1,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'

(и)

echo "aa,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'

НЕ производить какие-либо выходные данные в соответствии с требованием.

Еще один способ строгой проверки длины цифр, совместимый с POSIX, можно реализовать с помощью чего-то вроде приведенного ниже, где {3} обозначает длину совпадения.

echo "123,3" |  awk --posix -F, '$1 ~ /^[0-9]{3}$/'
123,3

(и)

echo "12,3" |  awk --posix -F, '$1 ~ /^[0-9]{3}$/'

не производит никакого вывода.

Если вы используете относительно новую версию оболочки bash, она поддерживает родной оператор regEx с классами символов ~ using POSIX, как указано выше, что-то вроде

#!/bin/bash

while IFS=',' read -r row1 row2
do
   [[ $row1 =~ ^([[:digit:]]+)$ ]] && printf "%s,%s\n" "$row1" "$row2"
done < file

Для входного файла скажите file

$ cat file
122,12
a1,22
aa,12

Скрипт производит,

$ bash script.sh
122,12

Хотя это работает, bash regEx может быть медленнее, относительно прямолинейный способ использования строковых манипуляций будет выглядеть примерно так:

while IFS=',' read -r row1 row2
do
   [[ -z "${row1//[0-9]/}" ]] && printf "%s,%s\n" "$row1" "$row2"
done < file

"${row1//[0-9]/}" удаляет все цифры из строки, и условие становится истинным только в том случае, если в переменной не осталось других символов.

person Inian    schedule 23.12.2016
comment
По какой-то причине эксперты рекомендуют использовать более идиоматичное awk, как в echo "123456789012345,3" | awk -F, '$1 ~ /^[[:digit:]]*$/'. Разве это не print здесь лишнее? - person sjsam; 23.12.2016
comment
@sjsam: Конечно да! Иногда при использовании собственной команды OP и изменении поверх нее некоторые мелкие детали теряются. Хороший улов однако! Не стесняйтесь редактировать его, это ваша истинная точка зрения! - person Inian; 23.12.2016
comment
Я не могу, поскольку вы уже рассказали, что не так с совпадением регулярных выражений op. Кстати, было бы интереснее, если бы у оператора был ввод типа echo ",3" | awk -F, '$1 ~ /^[[:digit:]]*$/' - person sjsam; 23.12.2016
comment
Поскольку OP использует версию 3.1.5 Gnu awk, вам, вероятно, следует добавить переключатель --posix в примеры квантификатора ({n,m}). - person James Brown; 23.12.2016
comment
@Все: Спасибо, ребята. Я нашел то, чего мне не хватало. echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]*)$/) print $0}' от @Ravinder или echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]+)$/) print $0}' от @Inian делают свое дело. - person dig_123; 23.12.2016

Здесь вы печатаете каждую строку, соответствующую шаблону. Это именно цель grep. Поскольку @Inian блестяще рассказал вам, что не так с вашим кодом, позвольте мне предложить альтернативный ответ на основе grep, который делает то же самое, что и команда awk (хотя и намного быстрее):

grep -E '^[[:digit:]]+,'
person xhienne    schedule 23.12.2016
comment
@ xhienne: Фактический файл, который мне нужно обработать, будет очень большим. Это причина использования awk. Я только что вынул строку кода из своего полного скрипта, чтобы избежать ненужной путаницы и четко понять, чего мне не хватает и чего я ожидаю. - person dig_123; 23.12.2016
comment
@ dig_123 Если ваш файл очень большой, это та самая причина, по которой вы предпочитаете grep вместо awk, что может быть более чем в 100 раз медленнее. Если вам не нужны расширенные функции в awk? Может быть, вы можете поставить свой awk на выходе grep, я думаю, вы увидите некоторое реальное ускорение. - person xhienne; 23.12.2016

Не могли бы вы попробовать следовать и дайте мне знать, если это поможет.

echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]*)$/)  print $0}'

EDIT: Приведенный выше код также можно немного сократить до следующего.

echo "123456789012345,3" | awk -F, '($1 ~ /^[[:digit:]]*$/)'
person RavinderSingh13    schedule 23.12.2016