Рекурсивный поиск файлов с определенным расширением

avatar
flip
8 мая 2011 в 12:21
559171
10
490

Я пытаюсь найти все файлы с определенным расширением в каталоге и его подкаталогах с помощью bash (последняя версия Ubuntu LTS).

Это то, что написано в файле сценария:

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

К сожалению, когда я запускаю этот скрипт в терминале, он говорит:

[: 29: in: unexpected operator

$extension вместо 'in')

Что здесь происходит, где ошибка? Но эта фигурная скобка

Источник
shrewmouse
20 ноября 2014 в 14:11
2

Ошибка из-за отсутствия символа "{"

Ответы (10)

avatar
kip2
15 июля 2019 в 16:14
12
find "$PWD" -type f -name "*.in"
avatar
Inian
5 августа 2018 в 14:55
9

Хотя здесь может быть полезно использование команды find, сама оболочка предоставляет параметры для выполнения этого требования без каких-либо сторонних инструментов. Оболочка bash предоставляет расширенную опцию поддержки glob, с помощью которой вы можете получить имена файлов по рекурсивным путям, которые соответствуют нужным вам расширениям.

Расширенный параметр - extglob, который необходимо установить с помощью параметра shopt, как показано ниже. Параметры включены с помощью поддержки -s и отключены с помощью флага -u. Кроме того, вы можете использовать еще несколько параметров, например nullglob, в котором несоответствующий глобус полностью удаляется и заменяется набором нулевых слов. И globstar, что позволяет рекурсивно просматривать все каталоги

shopt -s extglob nullglob globstar

Теперь все, что вам нужно сделать, это сформировать глобальное выражение для включения файлов определенного расширения, что вы можете сделать, как показано ниже. Мы используем массив для заполнения результатов glob, потому что при правильном цитировании и расширении имена файлов со специальными символами останутся нетронутыми и не будут повреждены из-за разделения слов оболочкой.

Например, чтобы перечислить все файлы *.csv в рекурсивных путях

fileList=(**/*.csv)

Параметр ** - это рекурсивный просмотр подпапок, а *.csv - расширение глобуса для включения любого файла с упомянутыми расширениями. Теперь для печати фактических файлов просто выполните

printf '%s\n' "${fileList[@]}"

Использование массива и правильное расширение кавычек - правильный путь при использовании в сценариях оболочки, но для интерактивного использования вы можете просто использовать ls с выражением glob как

ls -1 -- **/*.csv

Это вполне может быть расширено для соответствия нескольким файлам, то есть файлу, заканчивающемуся несколькими расширениями (то есть аналогично добавлению нескольких флагов в команде find). Например, рассмотрим случай, когда вам нужно получить все файлы рекурсивных изображений, то есть с расширениями *.gif, *.png и *.jpg, все, что вам нужно, это

ls -1 -- **/+(*.jpg|*.gif|*.png)

Это вполне может быть расширено, чтобы также иметь отрицательные результаты. С таким же синтаксисом можно использовать результаты glob для исключения файлов определенного типа. Предположим, вы хотите исключить имена файлов с указанными выше расширениями, вы можете сделать

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

Конструкция !() представляет собой операцию отрицания, чтобы не включать какие-либо расширения файлов, перечисленные внутри, а | - это оператор чередования, который используется в библиотеке расширенных регулярных выражений для сопоставления глобусов по ИЛИ.

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

avatar
Avinash Kumar Mishra
10 апреля 2018 в 05:52
1
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 
rollstuhlfahrer
10 апреля 2018 в 06:56
2

Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, улучшает его долгосрочную ценность.

avatar
rtrn
5 марта 2016 в 12:23
14

Без использования find:

du -a $directory | awk '{print $2}' | grep '\.in$'
Kenster
5 марта 2016 в 17:57
3

grep здесь на самом деле не нужен. awk имеет регулярные выражения и может ограничивать свой вывод значениями, соответствующими шаблону.

Protonova
11 февраля 2017 в 00:59
1

Этот метод чрезвычайно полезен, если вы используете сотни терабайт. Обработка команды поиска занимает слишком много времени. Это начинается немедленно.

Jens
30 июня 2017 в 16:50
1

awk|grep - это анти-шаблон. Позвольте awk делать grepping.

avatar
Sergiu
19 февраля 2015 в 08:14
1
find $directory -type f -name "*.in"|grep $substring
avatar
Bharat Yadav
20 ноября 2014 в 14:06
7

Чтобы найти все файлы pom.xml в текущем каталоге и распечатать их, вы можете использовать:

find . -name 'pom.xml' -print
avatar
Mohammad AlQanneh
23 августа 2014 в 17:29
237
find {directory} -type f -name '*.extension'

Пример: Чтобы найти все csv файлы в текущем каталоге и его подкаталогах, используйте:

find . -type f -name '*.csv'
avatar
Scott C Wilson
8 мая 2011 в 13:02
63

Синтаксис, который я использую, немного отличается от того, что предложил @Matt:

find $directory -type f -name \*.in

(на одно нажатие клавиши меньше).

Shnatsel
19 апреля 2013 в 09:25
1

Сценарий Мэтта также не будет работать, если в текущем каталоге есть файл с расширением .in, а ваш все равно будет работать. См. coderhelper.com/questions/5927369/…

gniourf_gniourf
19 февраля 2015 в 12:46
4

@Shnatsel, этот комментарий (и, следовательно, ваш) совершенно неверен.

Murmel
14 июня 2016 в 08:46
1

@gniourf_gniourf Вы должны предоставить некоторую ссылку для своего утверждения, иначе можно было бы просто возразить: «Нет, вы ошибаетесь». Но на самом деле вы правы: gnu.org/software/bash/manual/html_node/Double-Quotes.html

gniourf_gniourf
14 июня 2016 в 09:05
0

@ user1885518: Я думаю, что именно тот парень, который утверждает, что сценарий не работает, должен предоставить несколько примеров, когда сценарий не работает. Вот что я делаю, когда оставляю комментарии, где есть неработающие скрипты: обычно речь идет о кавычках и именах файлов, содержащих пробелы, новые строки, глобусы и т. Д., И я специально объясняю, почему это не работает.

Murmel
14 июня 2016 в 11:22
2

Ссылки - это всегда хороший способ обсуждения, это не зависит от того, кто был первым. Он должен, ты должен.

gniourf_gniourf
14 июня 2016 в 13:30
0

@ user1885518: этот парень явно ничего не знает о Bash и заявляет о самых глупых вещах. Вместо того, чтобы спрашивать, он просто констатирует заведомо неверные факты (вместо того, чтобы спрашивать). Это как если бы я зашел на сайт вопросов и ответов по шитью и заявил что-то глупое об иглах, нитках, пуговицах или ткани (я ничего не знаю о шитье). Люди просто говорили мне пойти и изучить основы шитья. И они, наверное, сказали бы это как-то агрессивно. Теперь, пожалуйста, оставьте меня в покое и перестаньте говорить мне, что мне делать; Я не буду больше читать об этом.

avatar
Jens
8 мая 2011 в 12:39
10
  1. После browsefolders () отсутствует {
  2. Все $in должны быть $suffix
  3. Строка с cut дает вам только среднюю часть front.middle.extension. Вам следует прочитать руководство по оболочке на ${varname%%pattern} и друзьях.

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

Для проверки правильности синтаксиса оболочки без запуска сценария используйте sh -n scriptname.

avatar
Mat
8 мая 2011 в 12:25
824
find $directory -type f -name "*.in"

немного короче всего этого (и безопаснее - имеет дело с пробелами в именах файлов и именах каталогов).

Ваш сценарий, вероятно, не работает с записями, в названии которых нет ., поэтому $extension становится пустым.

Mat
8 мая 2011 в 12:27
17

да, по умолчанию find рекурсивно. вы можете ограничить глубину, если хотите (см. справочную страницу).

flip
8 мая 2011 в 12:31
1

Я хочу передать все найденные файлы в качестве аргументов в jar-файл. Как это можно сделать?

Mat
8 мая 2011 в 12:33
8

@flip: это другой вопрос. Опубликуйте новый вопрос с подробным описанием того, что вы хотите сделать и что уже пробовали.

Shnatsel
19 апреля 2013 в 09:23
0

Одно небольшое исправление: используйте '* .in' или \ *. In вместо «* .in», потому что двойные кавычки не препятствуют раскрытию оболочки. Т.е. ваш сценарий не будет работать должным образом, если в текущем каталоге есть файл с расширением .in.

Mat
19 апреля 2013 в 12:25
4

@Shnatsel: двойные кавычки предотвращают расширение оболочки. Попробуйте сами.

Abdull
26 декабря 2013 в 19:55
0

Чтобы следовать символическим ссылкам, добавьте -L перед указанием пути, например: find -L $directory -type f -name "*.in"

Chandan Choudhury
27 октября 2014 в 07:57
0

Спасибо ... Я хотел бы знать, есть ли способ перечислить файлы * .in и * .ini ... то есть можем ли мы искать несколько расширений ... Также я не понимаю, почему нужно использовать '' или "" .. иначе написано - нет совпадения

Mat
27 октября 2014 в 08:38
0

@ChandanChoudhury: find . -type f -a \( -name '*.in' -o -name '*.ini' \); вам нужны кавычки, чтобы предотвратить подделку оболочки.

android developer
5 мая 2015 в 18:12
0

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

Mat
6 мая 2015 в 05:37
0

@androiddeveloper: man find - ваш друг. Поместите все свои пути в команду, работает нормально.

android developer
6 мая 2015 в 06:56
0

@ Мат У меня нет Linux. Хочу попробовать на Андроиде, но может и там "мужик" сработает. Каким должен быть разделитель между путями?

Mat
6 мая 2015 в 06:57
0

man - это команда, которую вы используете для чтения документации. Вы также можете ввести эту команду в поле поиска Google, работает нормально :-)

android developer
6 мая 2015 в 09:58
0

@Mat Это один: unixhelp.ed.ac.uk/CGI/man-cgi?find? вроде вариантов много ...