Использование grep, awk и csv для извлечения информации из текстовых файлов

Использование grep, awk и csv для извлечения информации из текстовых файлов

Я использую следующий код для извлечения информации из группы текстовых файлов (foo*.txt).

for file in foo*.txt; do 
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar.csv
done

Этот комментарий печатает нужные мне числа из кучи файлов (foo*.txt). Когда я пытаюсь напечатать и имя файла (в одном столбце файла csv), и номер (в следующем столбце файла csv), я попытался выполнить следующее в Терминале.

for file in foo*.txt; do 
echo $file
grep "some_text" $file | tail -n5 | awk '{print $2}' >> bar2.csv 
done

Это печатает имена файлов на терминале. Файл csv содержит нужные мне числа. Как можно изменить этот код так, чтобы имя файла печаталось в одном столбце, а извлеченные числа — в следующем столбце файла csv?

Другая проблема в этом коде — проблема сортировки. Например, рассмотрим имена файлов foo_01_s.txt, foo_02_s.txt, foo_03_s.txt.....foo_100_s.txt. Если я хочу извлечь информацию (используя комментарии выше), последний файл (foo_100_s.txt) не идет после foo_99_s.txt.

Решение с использованием Python/Perl также было бы полезным.

решение1

Вы должны понимать, что ваш >>перенаправит только часть текущей команды - в основном просто число, которое является результатом команды, начинающейся с grep, и переданной по конвейеру несколько раз. echo $fileявляется отдельной командой (вы используете ;) и, таким образом, обычно будет направлять на stdout. Все, что вам нужно сделать, это перенаправить после всего цикла:

for file in foo*.txt; do 
    echo $file
    grep "some_text" $file | tail -n5 | awk '{print $2}'
done > bar2.csv

Если вы хотите отсортировать файлы по версии (это подходящее название), вы можете перечислить их после сортировки:

for file in $(ls foo*.txt | sort -V); do

Для быстрого запуска чего-то небольшого (несколько минут для ~1000 файлов) этого должно быть достаточно.

РЕДАКТИРОВАТЬ

После вашего комментария есть несколько решений. Я предполагаю, что вы хотите:

file1 1
      2
      3

и т. д. Просто отбросьте echoи исправьте строку эха:

for file in foo*.txt; do 
    grep "some_text" $file | tail -n5 | awk -v f=$file '{if(NR==1) {printf("%-20s %-5s\n",f,\$2)} else {printf("%-20s %-5s\n","",$2)}}'
done > bar2.csv

Я позволяю awkделать печать за меня. Использование -vпозволяет мне передавать переменную в f. Для печати ознакомьтесь с printfсинтаксисом (вы можете использовать man printfв оболочке. По сути, я предполагаю два поля, одно с 20, другое 5 и пробел между ними. Знак «минус» выравнивает по левому краю. Вы можете поиграть с этим. Это решило бы вашу первоначальную проблему, так как теперь вы можете передать эту единственную строку по конвейеру.

Если вы хотите, чтобы файл был просто:

file1,1
file1,2
...
file2,1

Вы можете либо убрать это ifв моем awkутверждении, либо оставить первоначальное решение с echo, но использовать,

echo -n "$file,"

где -nгарантирует, что перевод строки не будет выведен.

Связанный контент