【问题标题】:Globbing/pathname expansion with colon as separator以冒号作为分隔符的通配符/路径名扩展
【发布时间】:2011-03-26 17:25:10
【问题描述】:

如何转换包含全局字符的字符串,例如

/var/lib/gems/*/bin

转换成与模式匹配的以冒号分隔的文件名字符串(即 PATH 兼容)?

echo /var/lib/gems/*/bin 将返回

/var/lib/gems/1.8/bin /var/lib/gems/1.9.1/bin

我想要

/var/lib/gems/1.8/bin:/var/lib/gems/1.9.1/bin 

改为。

显而易见的方法是通过tr 将空格字符替换为“:”,但如果文件名本身包含空格字符,则此方法不起作用。

【问题讨论】:

    标签: bash shell path glob expansion


    【解决方案1】:

    其实我想到了一个更好的解决方案:使用shell函数。

    function join() {
        local IFS=$1
        shift
        echo "$*"
    }
    
    mystring=$(join ':' /var/lib/gems/*/bin)
    

    【讨论】:

      【解决方案2】:

      这应该为你做:

      dirs=(/var/lib/gems/*/bin)    # put filenames (dirnames) in an array
      saveIFS=$IFS IFS=':'          # set the Internal Field Separator to the desired delimiter
      dirs=("${dirs[*]}")           # convert the array to a scalar with the new delimiter
      IFS=$saveIFS                  # restore IFS
      

      【讨论】:

        【解决方案3】:
        PATH="$(printf "%s:" /usr/*/bin)"
        PATH="${PATH%:}"
        

        【讨论】:

        • 这可行,但我会使用不同的变量。您也可以通过这种方式进行初始分配:printf -v varname "%s:" /var/lib/gems/*/bin
        • 几乎完美。我想我喜欢用管道连接 sed 以删除尾随冒号,尽管 ala stackoverflow.com/a/5074995/69002
        • @DennisWilliamson 那是一个漂亮的单线器。恕我直言,这应该是最佳答案。
        【解决方案4】:

        不用纠结IFS,zsh可以用一个简单的变量标志加入数组:

        dirs=(/var/lib/gems/*/bin(N))
        dirs=${(j.:.)dirs}
        

        如果没有文件,第一行的(N) 会抑制警告; (j.:.):s 加入数组。适用于 0、1 或多个匹配项。

        【讨论】:

        • @Michaël 不是我发现的,虽然 ZSH 确实经常让我感到惊讶,所以我不能肯定地说它不会。
        【解决方案5】:
        printf "%s\n" /var/lib/gems/*/bin | tr "\n" ":"
        

        【讨论】:

        • 关闭!但是如果只有一个匹配项,你会在最后得到一个冒号:“/var/lib/gems/1.9.1/bin:”。 (如果没有匹配,一个冒号。)
        【解决方案6】:

        如果你使用 Perl,这很简单:

        perl -e 'print join ":", @ARGV' /var/lib/gems/*/bin
        

        或 Python:

        python -c 'import sys; print ":".join(sys.argv[1:])' /var/lib/gems/*/bin
        

        或任何数量的其他流行脚本语言。

        【讨论】:

        • 看起来这可能是总体上最好的方法(IFS 摆弄有点乱),尽管不得不使用外部程序是一种耻辱......
        • 如果你想要单线,绝对是要走的路
        【解决方案7】:

        不保存 IFS 和命令替换

        dirs=(/var/lib/gems/*/bin) ; IFS=: eval 'dirs="${dirs[*]}"'
        

        【讨论】:

          【解决方案8】:

          另一个单线:printf "%s\n" /var/lib/gems/*/bin | paste -s -d':'

          但我认为@timo 的回答更好。

          【讨论】:

            猜你喜欢
            • 2010-12-12
            • 2013-03-10
            • 2016-09-26
            • 1970-01-01
            • 2013-04-23
            • 1970-01-01
            • 2023-03-06
            • 1970-01-01
            • 2019-02-22
            相关资源
            最近更新 更多