bash 如何递归地将子目录添加到 PATH?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/657108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to recursively add subdirectories to the PATH?
提问by user50264
How do you do it? My directory code/, at work, is organized in folders and subfolders and subsubfolders, all of which (at least in theory) contain scripts or programs I want to run on a regular basis.
你怎么做呢?我的目录code/在工作中被组织在文件夹、子文件夹和子文件夹中,所有这些(至少在理论上)都包含我想要定期运行的脚本或程序。
回答by paxdiablo
At the end of your script, put the line:
在脚本的末尾,放置以下行:
PATH=${PATH}:$(find ~/code -type d | tr '\n' ':' | sed 's/:$//')
This will append every directory in your ~/code tree to the current path. I don't like the idea myself, preferring to have only a couple of directories holding my own executables and explicitly listing them, but to each their own.
这会将 ~/code 树中的每个目录附加到当前路径。我自己不喜欢这个想法,更喜欢只有几个目录保存我自己的可执行文件并明确列出它们,但每个目录都有自己的。
If you want to exclude all directories which are hidden, you basically need to strip out every line that has the sequence "/."(to ensure that you don't check subdirectories under hidden directories as well):
如果你想排除所有隐藏的目录,你基本上需要去掉具有序列的每一行"/."(以确保你不检查隐藏目录下的子目录):
PATH=${PATH}:$(find ~/code -type d | sed '/\/\./d' | tr '\n' ':' | sed 's/:$//')
This will stop you from getting directories such as ~/code/level1/.hidden/level3/(i.e., it stops searching within sub-trees as soon as it detects they're hidden). If you only want to keep the hidden directories out, but still allow non-hidden directories under them, use:
这将阻止您获取诸如~/code/level1/.hidden/level3/(即,一旦检测到它们被隐藏就停止在子树中搜索)的目录。如果您只想将隐藏目录排除在外,但仍允许它们下存在非隐藏目录,请使用:
PATH=${PATH}:$(find ~/code -type d -name '[^\.]*' | tr '\n' ':' | sed 's/:$//')
This would allow ~/code/level1/.hidden2/level3/but disallow ~/code/level1/.hidden2/.hidden3/since -nameonly checks the base name of the file, not the full path name.
这将允许~/code/level1/.hidden2/level3/但不允许,~/code/level1/.hidden2/.hidden3/因为-name只检查文件的基本名称,而不是完整路径名。
回答by Charles Duffy
The following Does The Right Thing, including trimming hidden directories and their children and properly handling names with newlines or other whitespace:
以下是正确的做法,包括修剪隐藏目录及其子目录并正确处理带有换行符或其他空格的名称:
export PATH="${PATH}$(find ~/code -name '.*' -prune -o -type d -printf ':%p')"
I use a similar trick for automatically setting CLASSPATHs.
我使用类似的技巧来自动设置CLASSPATHs。
回答by altblue
If you really need to go down this road, you could try minimizing that PATHs list some more: drop folders that contain no executables. Of course, at the cost of even more stats. ;-/
如果你真的需要沿着这条路走下去,你可以尝试最小化路径列表:删除不包含可执行文件的文件夹。当然,以更多的统计数据为代价。;-/
PATH=$PATH$(find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' | sort | uniq | tr -d '\n')
I'd avoid doing this at each shell spawn. Some kind of caching should be used. For instance, add this line to your ~/.bashrc:
我会避免在每次 shell 生成时都这样做。应该使用某种缓存。例如,将此行添加到您的 ~/.bashrc 中:
[ -s ~/.codepath ] && export PATH=$PATH$(<~/.codepath)
and run
并运行
find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' |sort |uniq |tr -d '\n' > ~/.codepath
only when you know something really changed.
只有当你知道事情真的改变了。
EDIT: here's a rewrite without your missing -printf
编辑:这是一个没有丢失 -printf 的重写
find ~/code -name '.*' -prune -o -type f -a -perm /u+x -print | sed 's@/[^/]\+$@:@' | sort | uniq | tr -d '\n' | sed 's/^/:/; s/:$//'
回答by vrdhn
Something like
就像是
my_path=$(find $root -type d | tr '\n' ':')
or
或者
my_path=$(find $root -type d -printf '%p:')
回答by Kent Fredric
In bash 4.0 you can just use the newly supported **operator.
在 bash 4.0 中,您可以只使用新支持的**运算符。
You have to enable it first on some with :
您必须先启用它:
shopt -s globstar
You can then do
然后你可以做
echo **
which recursively echos all files that are descendant of the current dir.
它递归地回显当前目录的所有后代文件。
Beware it does tend to bail out on overly complicated dirs sometimes, so use the ** at the lowest recucurring point.
请注意,有时它确实倾向于避免过于复杂的目录,因此请在最低的重复点使用 **。
echo **/
Coincidentally, emits recursively all directory names, and only directory names. ( Excluding the current dir )
巧合的是,递归地发出所有目录名称,并且仅发出目录名称。(不包括当前目录)
echo ./**/
Includes the current dir. ( Incidentally, it also skips hidden directories )
包括当前目录。(顺便说一句,它还跳过隐藏目录)
This should thuswise be suited for creating a path string:
因此,这应该适用于创建路径字符串:
echo ./**/ | sed 's/\s\s*/:/g'
And if you don't want relative paths,
如果你不想要相对路径,
echo $PWD/**/ | sed 's/\s\s*/:/g'
Ack
确认
From your comment on one of the other posts it sounds like you're wanting behaviour much like 'Ack' provides. If you were intending to use a find + grep combination, this tool is generally much more efficient and easier to use for this task.
从您对其他帖子之一的评论来看,您似乎想要像“Ack”提供的那样的行为。如果您打算使用 find + grep 组合,则此工具通常更有效且更易于用于此任务。
Example:
例子:
# 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
回答by Mark
I've been looking for a solution to this problem too. It would be great if bash had a way to say that for certain paths, you want it to search for the files recursively. For example
我也一直在寻找这个问题的解决方案。如果 bash 有办法说对于某些路径,您希望它递归搜索文件,那就太好了。例如
PATH="$PATH:/usr/local/bin:~/bin**"
where ~/binwould search that directory and all of its subdirectories without making a mess out of your PATHvariable.
在哪里~/bin可以搜索该目录及其所有子目录,而不会弄乱您的PATH变量。
Since that's not implemented, my temporary solution is to put everything in my bin directory and then create another directory "bindir" that contains symbolic links to the actual executables in "bin", but their arranged neatly into subdirectories to make them easier to find.
由于没有实现,我的临时解决方案是将所有内容放在我的 bin 目录中,然后创建另一个目录“bindir”,其中包含指向“bin”中实际可执行文件的符号链接,但它们整齐地排列在子目录中,以便于查找。
My only question is whether I should hard links instead of symbolic links.
我唯一的问题是我是否应该使用硬链接而不是符号链接。
回答by R0ckyY2
Try this way:export PATH="$PATH:$(du "~/code/" | cut -f2 | tr '\n' ':' | sed 's/:*$//')"
This will add ~/code itself along with all its subdirectories into $PATH
Explanation:
- duwill display all the subdirectories info each line
- cut -f2will extract the second column, i.e., the names of the subdirectories
- tr '\n' ':'will change each link break into a colon. This will join all lines into a single line and the subdirectories are delimited by a colon
- sed 's/:*$//'will remove the last colon
尝试这种方式:export PATH="$PATH:$(du "~/code/" | cut -f2 | tr '\n' ':' | sed 's/:*$//')"
这会将 ~/code 本身及其所有子目录添加到 $PATH
说明:
-du将显示每行的所有子目录信息
-cut -f2将提取第二列,即子目录的名称
-tr '\n' ':'将更改每个链接中断变成冒号。这会将所有行合并为一行,子目录由冒号分隔
-sed 's/:*$//'将删除最后一个冒号
回答by Dimitre Radoulov
Something like this:
像这样的东西:
_path="$(
find <path> -name '.*' -prune -o -type d -print
)"
[[ $_path ]] && _path="${_path//$'\n'/:}" PATH="$PATH:${_path%:}"
If you have GNU find you may use -printf ':%p'directly.
如果你有 GNU find 你可以-printf ':%p'直接使用。
回答by Jonathan Leffler
I have a single bindirectory $HOME/binand that gets an installed copy of any programs I build (or scripts, or symlinks to programs or scripts). It currently has almost 600 commands in it (ls | wc -lsays 604, but there are a dozen or so sub-directories for various reasons).
我有一个bin目录$HOME/bin,它获取我构建的任何程序(或脚本,或程序或脚本的符号链接)的已安装副本。它目前有近 600 个命令(ls | wc -l说 604,但由于各种原因有十几个子目录)。
When I'm testing a program, I execute it where I build it; once I've done testing for the time being, I acquireit with my acquirescript, which copies the file and sets the permissions on it.
当我测试一个程序时,我会在我构建它的地方执行它;一旦我暂时完成了测试,我acquire就会使用我的acquire脚本来复制文件并设置它的权限。
This leaves me with a nice tidy profile (I don't use .bashrc; I'd rather do the setup once when the login shell starts, and the sub-shells inherit the working environment without having to parse .bashrcagain), but a rather ungainly bindirectory. It avoids the cost of resetting PATH each time a shell starts, for example, and given how complex my path-setting code is, that is just as well!
这给我留下了一个漂亮整洁的配置文件(我不使用.bashrc;我宁愿在登录 shell 启动时进行一次设置,并且子 shell 继承工作环境而不必.bashrc再次解析),但是一个相当笨拙的bin目录. 例如,它避免了每次 shell 启动时重置 PATH 的成本,并且考虑到我的路径设置代码有多么复杂,这也很好!

