Я использую следующий код для извлечения информации из группы текстовых файлов (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
гарантирует, что перевод строки не будет выведен.