【问题标题】:How to recursively add subdirectories to the PATH?如何递归地将子目录添加到 PATH?
【发布时间】:2010-10-14 00:20:59
【问题描述】:

你是怎么做到的?我的目录code/,在工作中,被组织在文件夹和子文件夹和子子文件夹中,所有这些(至少在理论上)都包含我想要定期运行的脚本或程序。

【问题讨论】:

    标签: bash file path


    【解决方案1】:

    类似

    my_path=$(find $root -type d | tr '\n' ':')
    

    my_path=$(find $root -type d -printf '%p:')
    

    【讨论】:

    • 非常。好的。有什么办法可以排除隐藏目录?我有一个 git repo,所以尝试一下,我得到的目录比我预期的要多:-/
    • 没有理由使用 '\n's find print -- 最好一开始就告诉它用冒号分隔文件。
    • @user50264 - 就像你用 git 做任何类型的排除一样;例如:find "$root" -name ".[a-z]*" -prune -o -type d -printf '%p:' 排除与给定模式匹配的点文件(排除 . 是不明智的,给定的 hack 是避免它的可行 80% 解决方案)。
    【解决方案2】:

    在 bash 4.0 中,您可以只使用新支持的 ** 运算符。

    您必须先在某些设备上启用它:

    shopt -s globstar
    

    你可以这样做

    echo ** 
    

    递归回显当前目录的所有后代文件。

    请注意,有时它确实倾向于解决过于复杂的目录,因此请在重复出现的最低点使用 **。

    echo **/  
    

    巧合的是,递归地发出所有目录名称,并且只发出目录名称。 (不包括当前目录)

    echo ./**/ 
    

    包括当前目录。 (顺便说一下,它也会跳过隐藏目录)

    因此这应该适合创建路径字符串:

    echo ./**/ | sed 's/\s\s*/:/g'
    

    如果你不想要相对路径,

    echo $PWD/**/ | sed 's/\s\s*/:/g' 
    

    确认

    从您对其他帖子之一的评论看来,您想要的行为很像“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  
    

    【讨论】:

    • 不知道其中任何一个,有没有办法制作任何一个输出目录?
    • 我喜欢这个简洁的解决方案,但是我想我可能有与你不同的 sed 版本,它用冒号替换了第一个“s”是每个目录。但是让我升级到 bash 4.0 的荣誉:)
    • O_o.那不是一个非常复杂的正则表达式:S。 \s\s* 应该只是替换空格。
    • @Kent - \s 是 PCRE 语法;基本 扩展 POSIX RE 都不支持它,因此标准 sed 不支持。
    • @Charles:你有没有测试过这个假设?您对“标准 Sed”的定义是什么?我的处理 \s 很好。 echo "hello world" | sed 's/\s/x/' 发出 helloxworld
    【解决方案3】:

    在你的脚本的最后,加上一行:

    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 只检查文件的基本名称,而不是完整路径名。

    【讨论】:

    • 很好,但与 Vardhan 的评论相同......那就是我需要排除隐藏目录。另外,将 tr 的结果传递给 sed 的目的是什么?
    • 你可能想要使用 find -print0 | tr "\0" ":" 代替 Pax,然后您将拥有一个过滤器,该过滤器应该适用于 ALL 有效的 unix 路径(包括其中带有讨厌的换行符的路径)
    • @Kent:不可打印的字符(包括空格)是邪恶的,如果我找到使用它们的人,我会用我的整个 IBM 大型机 COBOL 手册集将它们打死:- )
    • 如果您想娱乐,请在目录名称中添加哔声字符。你会知道房间里的 CD 里是否有人喜欢它;)
    • @Charles,然后给它投反对票并给另一个投赞成票。 “接受”(最好地解决了提问者的问题)和“最高票数”(我希望大多数人认为这是社区投票的最佳)之间存在差异。事实上,我之前曾提出过一个请求,要求查看最高票数高于接受的答案,但它被击退了。当然,这对你没有帮助,因为这个答案既获得了最高投票并且被接受,但可能不会永远如此。
    【解决方案4】:

    我有一个bin 目录$HOME/bin,它会获取我构建的任何程序(或脚本,或程序或脚本的符号链接)的已安装副本。它目前有近 600 个命令(ls | wc -l 说是 604,但由于各种原因有十几个子目录)。

    当我测试一个程序时,我会在我构建它的地方执行它;一旦我暂时完成了测试,我会使用我的acquire 脚本acquire 它,它会复制文件并设置其权限。

    这给我留下了一个漂亮整洁的配置文件(我不使用.bashrc;我宁愿在登录shell启动时进行一次设置,并且子shell无需解析@987654327即可继承工作环境@ 再次),但是一个相当笨拙的bin 目录。例如,它避免了每次 shell 启动时重置 PATH 的成本,并且考虑到我的路径设置代码有多复杂,这也是一样的!

    【讨论】:

      【解决方案5】:

      以下内容是正确的,包括修剪隐藏目录及其子目录以及正确处理带有换行符或其他空格的名称:

      export PATH="${PATH}$(find ~/code -name '.*' -prune -o -type d -printf ':%p')"
      

      我使用类似的技巧来自动设置CLASSPATHs。

      【讨论】:

      • 非常酷,没有调用 sed,因为 find 会为您处理一切......除了我有一个没有 printf 的 find 版本:-/
      【解决方案6】:

      类似这样的:

      _path="$(
        find <path> -name '.*' -prune -o -type d -print
        )" 
      
      [[ $_path ]] && _path="${_path//$'\n'/:}" PATH="$PATH:${_path%:}"   
      

      如果你有 GNU find 你可以直接使用-printf ':%p'

      【讨论】:

        【解决方案7】:

        如果您真的需要走这条路,您可以尝试将 PATH 列表最小化一些:删除不包含可执行文件的文件夹。当然,代价是更多的统计数据。 ;-/

        PATH=$PATH$(find ~/code -name '.*' -prune -o -type f -a -perm /u+x -printf ':%h\n' | sort | uniq | tr -d '\n')
        

        我会避免在每个 shell 生成时都这样做。应该使用某种缓存。例如,将此行添加到您的 ~/.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
        

        只有当您知道某些事情确实发生了变化时。

        编辑:这是一个没有丢失 -printf 的重写

        find ~/code -name '.*' -prune -o -type f -a -perm /u+x -print | sed 's@/[^/]\+$@:@' | sort | uniq | tr -d '\n' | sed 's/^/:/; s/:$//'
        

        【讨论】:

          【解决方案8】:

          我也一直在寻找解决这个问题的方法。如果 bash 有办法说对于某些路径,您希望它递归地搜索文件,那就太好了。例如

          PATH="$PATH:/usr/local/bin:~/bin**"
          

          ~/bin 将搜索该目录及其所有子目录,而不会弄乱您的 PATH 变量。

          由于没有实现,我的临时解决方案是将所有内容放在我的 bin 目录中,然后创建另一个目录“bindir”,其中包含指向“bin”中实际可执行文件的符号链接,但它们整齐地排列在子目录中以使它们更容易去寻找。

          我唯一的问题是我是否应该使用硬链接而不是符号链接。

          【讨论】:

            【解决方案9】:

            试试这个方法:
            export PATH="$PATH:$(du "~/code/" | cut -f2 | tr '\n' ':' | sed 's/:*$//')"
            这会将 ~/code 本身及其所有子目录添加到 $PATH
            说明:
            - du 将每行显示所有子目录信息
            - cut -f2 将提取第二列,即子目录的名称
            - tr '\n' ':' 会将每个链接中断更改为冒号。这会将所有行合并为一行,并且子目录由冒号分隔
            - sed 's/:*$//' 将删除最后一个冒号

            【讨论】:

              猜你喜欢
              • 2018-02-21
              • 2020-01-21
              • 2016-08-12
              • 1970-01-01
              • 1970-01-01
              • 2019-05-02
              • 2020-01-30
              • 2021-10-13
              • 1970-01-01
              相关资源
              最近更新 更多