2013-08-09 4 views
1
awk 'BEGIN{OFS=","} FNR == 1 
      {if (NR > 1) {print fn,fnr,nl} 
         fn=FILENAME; fnr = 1; nl = 0} 
         {fnr = FNR} 
         /ERROR/ && FILENAME ~ /\.gz$/ {nl++} 
         { 
          cmd="gunzip -cd " FILENAME 
          cmd; close(cmd) 
         } 
      END     {print fn,fnr,nl} 
     ' /tmp/appscraps/* > /tmp/test.txt 

вышеперечисленное сканирует все файлы в заданной директории. печатает имя файла, количество строк в каждом файле и количество найденных строк, содержащих «ERROR».Пытается модифицировать код awk

im теперь пытается сделать так, чтобы скрипт выполнял команду, если какой-либо файл, который он читает, не является обычным файлом. то есть, если файл является файлом gzip, затем выполните определенную команду.

это моя попытка включить команду gunzip и сделать это сама. к сожалению, он не работает. Кроме того, я не могу «вручную уничтожить» все файлы в каталоге заранее. это связано с тем, что не все файлы в каталоге будут «gzip». некоторые из них будут регулярными.

поэтому мне нужен сценарий для обработки любого файла .gz, он находит другой способ, чтобы он мог его прочитать, подсчитать и напечатать количество строк в нем, а также количество найденных строк, соответствующих найденному шаблону (просто как если бы файл был обычным файлом).

любая помощь?

+0

Термин «обычный файл» имеет техническое значение, а файл «gzip» является обычным файлом. Вы имеете в виду «текстовый файл». –

ответ

1

Эта часть вашего скрипта не имеет смысла:

 {if (NR > 1) {print fn,fnr,nl} 
        fn=FILENAME; fnr = 1; nl = 0} 
        {fnr = FNR} 
        /ERROR/ && FILENAME ~ /\.gz$/ {nl++} 

Позвольте мне перестроить его немного и прокомментировать его, чтобы он яснее, что он делает:

{ # for every line of every input file, do the following: 

    # If this is the 2nd or subsequent line, print the values of these variables: 
    if (NR > 1) { 
     print fn,fnr,nl 
    } 

    fn = FILENAME # set fn to FILENAME. Since this will occur for the first line of 
        # every file, this is that value fn will have when printed above, 
        # so why not just get rid of fn and print FILENAME? 

    fnr = 1   # set fnr to 1. This is immediately over-written below by 
        # setting it to FNR so this is pointless. 

    nl = 0 

} 
{ # for every line of every input file, also do the following 
    # (note the unnecessary "}" then "{" above): 

    fnr = FNR  # set fnr to FNR. Since this will occur for the first line of 
        # every file, this is that value fnr will have when printed above, 
        # so why not just get rid of fnr and print FNR-1? 
} 

/ERROR/ && FILENAME ~ /\.gz$/ { 

    nl++    # increment the value of nl. Since nl is always set to zero above, 
        # this will only ever set it to 1, so why not just set it to 1? 
        # I suspect the real intent is to NOT set it to zero above. 

} 

Вы также код выше тестирования для имени файла, которое заканчивается на «.gz», но затем вы запускаете gunzip для каждого файла в следующем блоке.

Помимо этого, просто вызовите gunzip из оболочки, как и все остальные. awk - инструмент для синтаксического анализа текста, это не среда, из которой можно вызвать другие инструменты - вот для чего предназначена оболочка.

Например, предполагается, что ваш комментарий (prints the file name, number of lines in each file and number of lines found containing 'ERROR) точно описывает то, что вы хотите, чтобы ваш скрипт AWK делать и предполагая, что это имеет смысл проверить слово «ERROR» непосредственно в «.gz» файл, используя AWK:

for file in /tmp/appscraps/*.gz 
do 
    awk -v OFS=',' '/ERROR/{nl++} END{print FILENAME, NR+0, nl+0}' "$file" 
    gunzip -cd "$file" 
done > /tmp/test.txt 

Гораздо понятнее и проще, не так ли?

Если это не имеет смысла, чтобы проверить для слова ERROR непосредственно в файле «.gz», то вы можете сделать это вместо:

for file in /tmp/appscraps/*.gz 
do 
    zcat "$file" | awk -v file="$file" -v OFS=',' '/ERROR/{nl++} END{print file, NR+0, nl+0}' 
    gunzip -cd "$file" 
done > /tmp/test.txt 

Для обработки GZ и не GZ файлы, как вы «в в настоящее время описано в своем комментарии ниже:

for file in /tmp/appscraps/* 
do 
    case $file in 
     *.gz) cmd="zcat" ;; 
     *) cmd="cat" ;; 
    esac 

    "$cmd" "$file" | 
     awk -v file="$file" -v OFS=',' '/ERROR/{nl++} END{print file, NR+0, nl+0}' 

done > /tmp/test.txt 

Я ушел из Gunzip, так как вам не нужно это, насколько я могу сказать от ваших заявленных требований. Если я ошибаюсь, объясните, для чего вам это нужно.

+0

Целью сценария является сканирование всех файлов в заданном каталоге и вывод ** имени файла, количества строк в файл и количество строк, соответствующих строке **. Я попытался добавить части о файлах «gz», потому что в каталоге есть также файлы gz, а не только текстовые файлы. поэтому я хотел объяснить это. Я попробовал другие предложения, которые были сделаны в этой теме, и они, похоже, не работали. Мне нужна статистика для каждого файла ... т. е. имя файла, количество строк, количество строк, соответствующих строке. это можно сделать, изменив мой оригинальный сценарий? – user99187

+0

Если вы «модифицируете мой оригинальный сценарий», вы имеете в виду скрипт awk - ну да, но это был бы полный беспорядок, включающий системные вызовы и getlines и всевозможные харты, чтобы заставить его получить вывод, который вы хотите не так путь. Я обновляю свой ответ, чтобы показать, как делать то, что я думаю, что вы ищете. –

0

Вы можете использовать выполнить следующую команду для каждого файла:

gunzip -t FILENAME; echo $? 

Он будет проходить печать код завершения 0 (для GZIP файлов) или 1 (коррумпированного/другого файла). Теперь вы можете сравнить результат с использованием IF для выполнения требуемой обработки.

1

Я думаю, что это может быть проще.

С расширением оболочки у вас уже есть имя файла (следовательно, вы можете его распечатать). Таким образом, вы можете сделать петлю на все файлы, и для каждого сделать следующее:

  • печати имени файла
  • zgrep -c ERROR $ файл (это выводит количество строк, содержащих «Ошибка»)
  • zcat $ файл | туалет -l (это выведет номера строк)

zgrep и zcat работа на обоих текстовых файлов и с gzip'нутыми из них.

Предполагая, что у вас нет каких-либо пробелов в пути/имени файла:

for f in /tmp/appscraps/* 
do 
    n_lines=$(zcat "$f"|wc -l) 
    n_errors=$(zgrep -c ERROR "$f") 
    echo "$f $n_lines $n_errors" 
done 

Это непроверенный, но он должен работать.

+2

Я считаю, что не будет беспокоить имена файлов с пробелами, поэтому вам не нужно изменять IFS. Вам нужно процитировать переменную, хотя: '' $ f "' –

+0

Спасибо Glenn, отредактированный с помощью вашего предложения –

Смежные вопросы