Bash: рекурсивно добавление подкаталогов в путь
Как вы это делаете? Мой код/каталог на работе организован в папках и подпапках и подпапках, все из которых (по крайней мере теоретически) содержат сценарии или программы, которые я хочу запускать на регулярной основе.
Его превращение моего иначе живописного .bashrc в бельмо!
Спасибо!
Ответы
Ответ 1
В конце вашего script поместите строку:
PATH=${PATH}:$(find ~/code -type d | tr '\n' ':' | sed 's/:$//')
Это добавит каждый каталог в дерево ~/code к текущему пути. Мне не нравится сама идея, предпочитая иметь только пару каталогов, содержащих мои собственные исполняемые файлы и явно перечисляя их, но каждому из них.
Если вы хотите исключить все скрытые каталоги, вам в основном нужно выделить каждую строку с последовательностью "/."
(чтобы гарантировать, что вы также не проверяете подкаталоги в скрытых каталогах):
PATH=${PATH}:$(find ~/code -type d | sed '/\/\\./d' | tr '\n' ':' | sed 's/:$//')
Это остановит вас от получения каталогов, таких как ~/code/level1/.hidden/level3/
(т.е. прекратит поиск в поддеревах, как только он обнаружит, что они скрыты). Если вы хотите сохранить скрытые каталоги, но по-прежнему разрешать скрытые каталоги, используйте:
PATH=${PATH}:$(find ~/code -type d -name '[^\.]*' | tr '\n' ':' | sed 's/:$//')
Это позволило бы ~/code/level1/.hidden2/level3/
, но запретить ~/code/level1/.hidden2/.hidden3/
, поскольку -name
проверяет только базовое имя файла, а не полное имя пути.
Ответ 2
Ниже перечислены "Правильные вещи", включая обрезку скрытых каталогов и их детей и правильное обращение с именами с символами перевода строки или другими пробелами:
export PATH="${PATH}$(find ~/code -name '.*' -prune -o -type d -printf ':%p')"
Я использую подобный трюк для автоматической установки CLASSPATH
s.
Ответ 3
Что-то вроде
my_path=$(find $root -type d | tr '\n' ':')
или
my_path=$(find $root -type d -printf '%p:')
Ответ 4
Если вам действительно нужно спуститься по этой дороге, вы можете попытаться свести к минимуму, что список PATHs еще больше: отбросить папки, которые не содержат исполняемых файлов. Конечно, ценой еще больше статистики.; -/
PATH=$PATH$(find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' | sort | uniq | tr -d '\n')
Я бы избегал делать это на каждом икру оболочки. Необходимо использовать какое-то кеширование. Например, добавьте эту строку в свой файл ~/.bashrc:
[ -s ~/.codepath ] && export PATH=$PATH$(<~/.codepath)
и запустите
find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' |sort |uniq |tr -d '\n' > ~/.codepath
только когда вы знаете что-то действительно изменившееся.
EDIT: здесь переписывается без вашего отсутствующего -printf
find ~/code -name '.*' -prune -o -type f -a -perm /u+x -print | sed '[email protected]/[^/]\[email protected]:@' | sort | uniq | tr -d '\n' | sed 's/^/:/; s/:$//'
Ответ 5
В bash 4.0 вы можете просто использовать только что поддерживаемый оператор **
.
Вы должны сначала включить его с помощью:
shopt -s globstar
Затем вы можете сделать
echo **
который рекурсивно отображает все файлы, которые являются потомками текущего каталога.
Остерегайтесь, что он иногда пытается спастись от чрезмерно сложных dirs, поэтому используйте ** в самой низкой точке recucurring.
echo **/
Кстати, испускает рекурсивно все имена каталогов и только имена каталогов. (Исключая текущий каталог)
echo ./**/
Включает текущий каталог. (Кстати, он также пропускает скрытые каталоги)
Это должно быть соответствующим образом для создания строки пути:
echo ./**/ | sed 's/\s\s*/:/g'
И если вам не нужны относительные пути,
echo $PWD/**/ | sed 's/\s\s*/:/g'
Ack
Из вашего комментария к одному из других сообщений это звучит так, как будто вы хотите, чтобы поведение было похоже на "Ack". Если вы намеревались использовать комбинацию find + grep, этот инструмент, как правило, намного эффективнее и проще в использовании для этой задачи.
Пример:
# search for 'mystring' in all c++ files recursively ( excluding SCM dirs and backup files )
ack "mystring" --type=cpp
# finds all text files not in an SCM dir ( recursively) and not a backup using type heuristics.
ack -f --type=text
Ответ 6
Я тоже искал решение этой проблемы. Было бы здорово, если бы bash имел способ сказать, что для определенных путей вы хотите, чтобы он искал файлы рекурсивно. Например
PATH="$PATH:/usr/local/bin:~/bin**"
где ~/bin
будет искать этот каталог и все его подкаталоги, не создавая беспорядок из вашей переменной PATH
.
Так как это не реализовано, мое временное решение состоит в том, чтобы поместить все в мой каталог bin и затем создать другой каталог "bindir", который содержит символические ссылки на фактические исполняемые файлы в "bin", но их аккуратно размещены в подкаталогах, чтобы упростить их найти.
Мой вопрос только в том, нужны ли мне жесткие ссылки вместо символических ссылок.
Ответ 7
У меня есть один каталог bin
$HOME/bin
, и он получает установленную копию любых создаваемых мной программ (или скриптов или символических ссылок на программы или скрипты). В настоящее время в нем имеется почти 600 команд (ls | wc -l
говорит 604, но по разным причинам существует около дюжины подкаталогов).
Когда я тестирую программу, я запускаю ее там, где я ее создаю; как только я уже тестировал, я acquire
с моим acquire
script, который копирует файл и устанавливает для него права.
Это оставляет мне хороший аккуратный профиль (я не использую .bashrc
, я бы предпочел выполнить настройку один раз, когда начинается оболочка входа, а подчиненные оболочки наследуют рабочую среду без необходимости синтаксического анализа .bashrc
снова), но довольно неуклюжий каталог bin
. Это позволяет избежать затрат на перезагрузку PATH каждый раз, когда запускается оболочка, например, и учитывая, насколько сложным мой код настройки пути, это тоже хорошо!
Ответ 8
Что-то вроде этого:
_path="$(
find <path> -name '.*' -prune -o -type d -print
)"
[[ $_path ]] && _path="${_path//$'\n'/:}" PATH="$PATH:${_path%:}"
Если у вас есть поиск GNU, вы можете напрямую использовать -printf ':%p'
.