Bash - Как прекратить поиск глубже после того, как файл найден?

Я пытаюсь выполнить это, используя собственные функции bash без поиска и т. д.

В настоящее время я:

  1. Получение списка всех имен файлов и помещение их в массив.
  2. Разбор их с регулярным выражением, чтобы найти определенное имя файла
  3. Затем добавляю эти совпадения в другой массив, который я использую позже в сценарии.

Я хотел бы немного изменить это, чтобы прекратить поиск глубже в дереве, если я найду совпадение. то есть, скажем, файл, который я ищу, это «test.txt»

И у меня есть следующие файлы:

./stuff/test.txt
./stuff/things/test.txt
./foo/bar/test.txt

Я хотел бы сопоставить только ./stuff/test.txt, игнорировать ./stuff/things/test.txt (поскольку он имеет родительское совпадение) и по-прежнему находить ./foo/bar/test.txt как его в другом дерево из первого матча.

Не слишком уверены, что лучше всего использовать собственный bash без внешних приложений? Ценил бы некоторую мудрость в отношении наилучшего подхода.

Вот мой текущий код:

shopt -s globstar

    for files in **/*; do
        if [[ -f "${files}" ]]; then
            files_array+=(\./"${files}")
        fi
    done

shopt -u globstar

shopt -s nocasematch

    for such_files in "${files_array[@]}"; do
        if [[ "${such_files}" =~ ${my_custom_regex} ]]; then
            full_projects+=("${such_files}")
        fi
    done

shopt -u nocasematch`

Как бы то ни было, вы ничего не можете сделать, чтобы избежать спуска в каталог, потому что **/* расширяется до того, как запустится какая-либо ваша логика. Если вы хотите сделать это, как указано, вам придется вручную написать рекурсивную функцию, которая условно пропускает спуск в каталоги, которые вам не нужны.

that other guy 12.12.2020 05:27

@that-other-guy Спасибо, что заглянули! Да, я знаю, что мне нужно провести рефакторинг, просто не слишком уверен в лучшем подходе? Я подумал, что, возможно, пропускаю совпадения регулярных выражений через фильтр другого типа, чтобы удалить все повторяющиеся подпапки, а затем снова сохранить их. Просто любопытно, есть ли идиоматический способ сделать такие вещи.

OctopusNZ 12.12.2020 07:17

Нет, нет. Даже с find это непросто реализовать, если имя файла не известно, например test.txt.

oguz ismail 12.12.2020 08:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне удалось сделать это, используя несколько функций и массивов. Это самый эффективный способ? Не очень уверен, но пока работает.

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

  1. Проверьте, из каких файлов в текущем каталоге выполняется скрипт. Если мы найдем совпадение, у нас все хорошо, и мы можем выйти.
  2. Если совпадений нет, мы перечисляем каталоги в текущем каталоге. Затем перебирайте их, проверяя совпадения.
  3. Если мы найдем совпадение, мы перестанем нырять. Если мы этого не сделаем, мы будем продолжать нырять вниз по этому дереву, пока не закончатся каталоги.

Больше примеров с некоторыми работающими скриптами здесь: https://github.com/octopusnz/scripts

Вот мой код:

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

magic_reg = "my_fancy_regex"
reg_matches=()
tmp_array=()
success=0

main(){

    shopt -s nocasematch

    for files in *; do
        if [[ -f "${files}" ]]; then
            if [[ "${files}" =~ ${magic_reg} ]]; then
                reg_matches+=("${PWD}")
                success=$((success+1))
                #This will only find the first one
                break
            fi
        fi
    done

    shopt -u nocasematch

    if [[ "${success}" -gt 0 ]]; then
        cleanup
    fi
}

deeper_dirs(){

  set +o nounset

  if [[ "${#tmp_array[@]}" -gt 0 ]]; then
      for deeper_files in "${tmp_array[@]}"; do
          cd "${deeper_files}"
          cust_get_files
      done
  fi

  set -o nounset

}

cust_get_files() {

    shopt -s nocasematch
    success=0

    for files in *; do
        if [[ -f "${files}" ]]; then
            if [[ "${files}" =~ ${magic_reg} ]]; then
                reg_matches+=("${deeper_files}")
                success=$((success+1))
                #This will only find the first one
                break
            fi
        fi
    done

    shopt -u nocasematch

    if [[ "${success}" -eq 0 ]]; then
        unset tmp_array
        for dirs in *; do
            if [[ -d "${dirs}" ]]; then
                tmp_array+=("${PWD}"/"${dirs}")
            fi
        done
        deeper_dirs
    fi
}

dir_check() {

    for dirs in *; do
        if [[ -d "${dirs}" ]]; then
            dirs_array+=("${PWD}"/"${dirs}")
        fi
    done

    for deeper_files in "${dirs_array[@]}"; do
        cd "${deeper_files}"
        cust_get_files
    done
}

cleanup() {

    if [[ "${#reg_matches[@]}" -lt 1 ]]; then
        printf "We didn't find any matching files. Nothing to do.\n"
        exit 0
    fi

    echo "${reg_matches[@]}"
    # We can do more neat stuff with this data here.

    exit 0
}

main
dir_check
cleanup

Другие вопросы по теме