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