Bash - Поиск выборочных файлов в списке файлов - PullRequest
0 голосов
/ 23 октября 2019

У меня есть список из n файлов, все они имеют одинаковые имена, кроме номеров (например, file_1, file_2, file_3 ... file_n). Однако не все эти файлы меня интересуют, только некоторые, потому что только некоторые имеют молекулярные структуры, которые мне нужны. Однако в этом наборе из n файлов я точно не знаю, какие из них имеют необходимую структуру (обратите внимание, что у каждого файла есть только одна структура).

Как лучше всего определить, какой файл имеетструктура мне нужна? Мне просто нужно их идентифицировать. Я думал о создании двух векторов, один с именами всех файлов и один со словами, которые идентифицируют молекулы (слова, которые находятся внутри файла, можно найти с помощью команды grep).

Я думал о созданииОднако в двух циклах с этими двумя векторами я обнаружил проблемы в этой попытке.

L='1 2 3 4 5 6 n'

M='molecule1 molecule2 molecule3...'

for l in $L
do
    for m in $M
    do
        echo "$l" >> files.gjf
        grep "$m" file_$l.gjf >> files.gjf
    done
done

Проблема этих двух циклов заключается в том, что у меня есть очень большой набор файлов, а также молекул, поэтому команда echoЯ использую для определения файлов, которые мне нужны, делает мой вывод очень большой. Тест, который я провел с вектором из 500 файлов, и только 51 молекула сгенерировала вывод (files.gjf) с 24013 строками.

Могу ли я использовать другой код, чтобы сделать его более надежным способом?

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

grep может искать несколько строк за один раз, а с -l может прекратить поиск, как только найдет первую строку в каждом файле и сообщить об этом файле как о совпадении. Так что, возможно, вы просто ищете

grep -l -E 'molecule1|molecule2|molecule3|.....' file_1.gjf file_2.gjf file_3.gjf ... >files.gjf

Если вы просто хотите найти все файлы, соответствующие шаблону file_*.gjf, тогда это очевидное и простое упрощение.

Это не позволит вамПосмотрите, какая именно строка поиска была найдена, хотя простое удаление -l исправит это (но затем сгенерирует больше выходных данных и распечатает все совпадения с именем файла перед каждым совпадением; таким образом, потенциально больше выходных данных, чем вашпервоначальная попытка, если совпадений много).

Я использовал опцию -E, чтобы включить другой синтаксис шаблона, который упрощает указание множества строк поиска в одном шаблоне. Вы также можете захотеть взглянуть на -f, который позволяет вам помещать шаблоны в файл (и, возможно, также -F для обработки каждого шаблона как буквенной строки, а не регулярного выражения).

printf '%s\n' molecule1 molecule2 molecule3 ... |
grep -Ff - -l file_*.gjf >files.gjf

Здесь мы предоставляем шаблоны "файл" на стандартном вводе (условно представленные псевдонимом - во многих командах Unix) вместо хранения их в физическом файле. Возможно, запустите часть printf в отдельности, чтобы посмотреть, что она производит.

Кроме того, ваши вложенные циклы можно сделать более эффективными, перемещая перенаправление после последнего done. Каждый >> внутри основного цикла будет открывать файл для записи и искать до конца на каждой итерации. Это довольно быстрая операция на современных компьютерах, но она по-прежнему не нужна.

for thing in list of things; do  # really no point in using a variable
    for other in more stuff; do
        echo "$thing"
        grep "$other" "file_$thing"
    done
done >result

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

1 голос
/ 23 октября 2019

Я бы структурировал это следующим образом. Я бы использовал массив для хранения ключевых слов, которые вы ищете.

declare -a a_keywords 
a_keywords="word1 word2 etc" 

Затем я перебрал бы элементы в этом массиве:

for (( i = 0 ; i < ${#a_keywords[@]} ; i++ )) ; do 

, а затем выполнил бы grep для каждого результата:

    grep -r "${a_keywords[i]}" /path/to/root/folder/for/your/files/ 

Закройте цикл for (с done).

Если вы используете вышеуказанную структуру для загрузки массива (declare -a a_keywordsResults), тогда вы можете grep "${a_keywordsResults[@]}" использовать свой массивчисел (declare -a a_keyNumbs) в аналогичном цикле for.

Вы можете изменить эту структуру (сначала grep для Numbs, а затем grep для Results для слов), но это будет зависеть от того, какой из них может быть более эффективнымдля вашей конкретной ситуации.

Если вам нужен вывод окончательных результатов (тех, которые проходят оба greps), вы можете после всего вышеперечисленного передать то, что осталось в файл.

Если я 'мы неправильно поняли вашу цель, дайте мне знать.

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