#bash
#bash
Вопрос:
Я пытаюсь выполнить это, используя встроенную функциональность bash без поиска и т. Д.
В настоящее время я:
- Получение списка всех имен файлов и помещение их в массив.
- Анализируем их по регулярному выражению, чтобы найти конкретное имя файла
- Затем добавьте эти совпадения в другой массив, который я использую позже в скрипте
Я хотел бы немного изменить это, чтобы прекратить поиск глубже в дереве, если я найду совпадение. т.е. допустим, файл, который я ищу, ‘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`
Комментарии:
1. Как есть, вы ничего не можете сделать, чтобы избежать перехода в каталог, потому
**/*
что он расширяется до запуска любой вашей логики. Если вы хотите сделать это, как указано, вам придется вручную написать рекурсивную функцию, которая условно пропускает переход в каталоги, которые вам не нужны.2. @that-other-guy Спасибо, что взглянули! Да, я знаю, что мне нужно провести рефакторинг, просто не слишком уверен в лучшем подходе? Я подумал, может быть, передать совпадения регулярных выражений через фильтр другого типа, чтобы удалить все дублирующиеся подпапки, а затем сохранить их снова. Просто любопытно, есть ли идиоматический способ сделать что-то подобное.
3. Нет, нет. Даже с
find
этим нелегко реализовать, если имя файла не известно, напримерtest.txt
.
Ответ №1:
Мне удалось сделать это, используя несколько функций и массивов. Это самый эффективный способ? Не слишком уверен, но пока работает.
Предполагая, что скрипт может быть запущен из любого места, а затем будет погружаться в дерево каталогов, пока не найдет совпадение регулярных выражений, мы:
- Проверьте все файлы в текущем каталоге, из которых выполняется скрипт. Если мы найдем совпадение, у нас все хорошо, и мы можем выйти.
- Если совпадений нет, мы перечисляем каталоги в текущем каталоге. Затем выполните итерацию в них, проверяя совпадения.
- Если мы находим совпадение, мы прекращаем погружение. Если мы этого не сделаем, мы продолжаем погружаться в это дерево, пока не останется больше каталогов.
Больше примеров с некоторыми рабочими сценариями здесь: 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