Как проверить информацию, используя стандартные фильтры linux / unix? - PullRequest
1 голос
/ 06 октября 2009

У меня есть следующие данные в файле с разделителями табуляции:

_ ДАННЫЕ _

Col1    Col2     Col3     Col4    Col5
blah1   blah2     blah3   4       someotherText
blahA   blahZ     blahJ   2       someotherText1
blahB   blahT     blahT   7       someotherText2
blahC   blahQ     blahL   10      someotherText3

Я хочу убедиться, что данные в 4-м столбце этого файла всегда целочисленные. Я знаю как это сделать в perl

  • Прочитать каждую строку, сохранить значение 4-го столбца в переменной
  • проверить, является ли эта переменная целым числом
  • если приведенное выше верно, продолжить цикл
  • иначе вырваться из цикла с сообщением о том, что данные файла неверны

Но как мне сделать это в сценарии оболочки, используя стандартный фильтр linux / unix? Мое предположение было бы использовать grep, но я не уверен, как?

Ответы [ 9 ]

7 голосов
/ 06 октября 2009
cut -f4 data | LANG=C grep -q '[^0-9]' && echo invalid
  • LANG = C для скорости
  • -q для выхода при первой ошибке в возможном длинном файле

Если вам нужно убрать первую строку, используйте tail -n + 2, иначе вы можете получить хак и использовать:

cut -f4 data | LANG=C sed -n '1b;/[^0-9]/{s/.*/invalid/p;q}'
2 голосов
/ 06 октября 2009

awk - инструмент, наиболее естественно подходящий для разбора по столбцам:

awk '{if ($4 !~ /^[0-9]+$/) { print "Error! Column 4 is not an integer:"; print $0; exit 1}}' data.txt

По мере усложнения процесса обнаружения ошибок вы, вероятно, захотите поместить сценарий awk в файл и вызвать его с помощью awk -f verify.awk data.txt.

Редактировать: в форме, которую вы поместите в verify.awk:

{
    if ($4 !~/^[0-9]+$/)  {
        print "Error! Column 4 is not an integer:"
        print $0
        exit 1
    }
}

Обратите внимание, что я сделал выход awk с ненулевым кодом, чтобы вы могли легко проверить это в своем вызывающем скрипте с помощью чего-то вроде этого в bash:

if awk -f verify.awk data.txt; then
     # action for success
else
     # action for failure
fi

Вы можете использовать grep, но он не распознает столбцы. Вы застряли бы писать шаблоны, соответствующие столбцам.

1 голос
/ 06 октября 2009

Pure Bash:

linenum=1; while read line; do field=($line); if ((linenum>1)); then [[ ! ${field[3]} =~ ^[[:digit:]]+$ ]] && echo "FAIL: line number: ${linenum}, value: '${field[3]}' is not an integer"; fi; ((linenum++)); done < data.txt

Чтобы остановиться на первой ошибке, добавьте break:

linenum=1; while read line; do field=($line); if ((linenum>1)); then [[ ! ${field[3]} =~ ^[[:digit:]]+$ ]] && echo "FAIL: line number: ${linenum}, value: '${field[3]}' is not an integer" && break; fi; ((linenum++)); done < data.txt
1 голос
/ 06 октября 2009

Иногда вам нужен только BASH, потому что tr, cut & awk ведут себя по-разному в Linux / Solaris / Aix / BSD / etc:

while read a b c d e ;  do [[ "$d" =~ ^[0-9] ]] || echo "$a: $d not a numer" ;  done < data
1 голос
/ 06 октября 2009

awk - это то, что вам нужно.

Я пока не могу проголосовать, но я бы проголосовал, если смогу. Джефроми.

1 голос
/ 06 октября 2009

Edited ....

#!/bin/bash

isdigit ()
{
    [ $# -eq 1 ] || return 0

    case $1 in
        *[!0-9]*|"") return 0;;
        *) return 1;;
    esac
}

while read line
do
    col=($line)
    digit=${col[3]}

    if isdigit "$digit"
    then
        echo "err, no digit $digit"
    else
        echo "hey, we got a digit $digit"
    fi
done

Используйте это в скрипте foo.sh и запустите его как ./foo.sh См. tldp.org для получения дополнительной информации

0 голосов
/ 07 октября 2009

@ OP, используйте awk

awk '$4+0<=0{print "not ok";exit}' file
0 голосов
/ 06 октября 2009

Имейте в виду, это может быть не самым эффективным по сравнению с повторением файла с чем-то вроде perl.

tail +2 x.x | sort -n -k 4 | head -1 | cut -f 4 | egrep "^[0-9]+$"
if [ "$?" == "0" ]
then
    echo "file is ok";
fi

tail +2 дает вам все, кроме первой строки (так как ваш образец имеет заголовок) sort -n -k 4 сортирует файл численно по 4-му столбцу, буквы будут подниматься вверх. Глава -1 дает вам первую строку файла cut -f 4 дает вам 4-й столбец первой строки egrep "^ [0-9] + $" проверяет, является ли значение числом (в данном случае целыми числами).

Если egrep ничего не находит, $? равно 1, в противном случае это 0.

Также есть:

if [ `tail +2 x.x | wc -l` == `tail +2 x.x | cut -f 4 | egrep "^[0-9]+$" | wc -l` ] then
    echo "file is ok";
fi

Это будет быстрее, требуя двух простых проверок файла, но это не один конвейер.

0 голосов
/ 06 октября 2009
cut -f 4 filename

вернет четвертое поле каждой строки в стандартный вывод.

Надеюсь, это хорошее начало, потому что прошло много времени с тех пор, как мне приходилось делать какие-либо серьезные сценарии оболочки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...