【问题标题】:How do I get a list of directories in bash and then expand them as command line parameters?如何在 bash 中获取目录列表,然后将它们扩展为命令行参数?
【发布时间】:2011-09-21 17:08:37
【问题描述】:

我正在编写一个 bash 脚本,它需要在一个步骤中获取目标目录(也可能包含文件)中的目录(变量)列表,然后将它们作为参数展开到 python 脚本。

例子:

/stuff/a dir/
/stuff/b other/
/stuff/c/

我需要在 bash 脚本中调用:

script.py "a dir/" "b other/" "c/"

或者,转义空格:

script.py a\ dir/ b\ other/ c/

我需要为目录“stuff”只调用一次脚本。

有没有一种简单的方法来做这种事情?我一直在谷歌搜索,我设法弄清楚的最好的方法是让我知道有多少个目录。

【问题讨论】:

    标签: bash command-line-arguments


    【解决方案1】:

    您可以使用 find 命令并告诉它只打印带有 -type d 的目录。您的命令将如下所示:

    script.py $(find /stuff/* -type d)
    

    如果您担心空格和其他特殊字符,可以这样做:

    script.py $(find /stuff/* -type d | while read line; do echo "\"$line"\"; done)
    

    【讨论】:

    • 有没有办法将单个输出用引号括起来,以便正确处理目录名称中的空格?
    【解决方案2】:

    这是一项寻找工作。

    find /stuff -type d -exec script.py {} +
    

    当您使用-exec 时,花括号{} 被替换为匹配文件的名称,+ 表示命令结束(如果您想告诉 find 采取其他操作)。这是使用 find 执行命令的理想方式,因为它将正确处理带有不寻常字符(例如空格)的文件名。

    find 非常灵活,特别是如果您拥有通常与 Linux 发行版捆绑的 GNU 版本。

    # Don't recurse into subdirectories.
    find /stuff -maxdepth 1 -type d -exec script.py {} +
    
    # Pass in a/, b/, c/ instead of /stuff/a/, /stuff/b/, /stuff/c/.
    find /stuff -type d -printf '%P\0' | xargs -0 script.py
    

    在第二个示例中,注意谨慎使用\0xargs -0 来使用NUL 字符来分隔文件名。这可能看起来很奇怪,但是即使您做了一些非常奇怪的事情,例如在目录名称中使用换行符 \n,这也允许该命令工作。


    或者,您可以仅使用 shell 内置函数来执行此操作。我不建议这样做,但出于教育价值,方法如下:

    # Start with an empty array.
    DIRS=()
    
    # For each file in /stuff/...
    for FILE in /stuff/*; do
        # If the file is a directory add it to the array. ("&&" is shorthand for
        # if/then.)
        [[ -d $FILE ]] && DIRS+=("$FILE")
    
        # (Normally variable expansions should have double quotes to preserve
        # whitespace; thanks to bash magic we don't them inside double brackets.
        # [[ ]] has special parsing rules.)
    done
    
    # Pass directories to script. The `"${array[@]}"` syntax is an unfortunately
    # verbose way of expanding an array into separate strings. The double quotes
    # and the `[@]` ensure that whitespace is preserved correctly.
    script.py "${DIRS[@]}"
    

    【讨论】:

    • 请记住 find 将递归到目录中。你需要-maxdepth 1。此外,-exec script.py {} + 可能会多次调用脚本,如果有很多目录。从问题中不清楚是否可以。
    • 有点跑题了,但为什么不建议只使用 shell 内置函数呢?
    • @Charles Randall: Re 'builtin' vs 'not-builtin' .. find 有一些特别有用的文件处理功能;比“内置”更重要,例如在处理嵌入空间的文件名时(参见man find 中的-print0),以及exec 的能力。有关内置的​​方式/内容/原因的更多信息,请参阅: unix.stackexchange.com/questions/11454/…
    • @Charles 我并不是要暗示仅 bash 的脚本不好。这是非常好的代码,没有我所知道的缺陷。它只是比使用find 更冗长,仅此而已。
    【解决方案3】:
    find /stuff/* -type d -maxdepth 1 -print0 | xargs -0 script.py
    

    这将找到 /stuff 下的所有目录,但不是递归的,并将它们传递给 script.py 并确保它们正确传递,即使目录名称中有空格。

    【讨论】:

    • 这几乎可以工作,只是它还在输出中列出 /stuff,这会给我带来问题。
    • 根据您的评论更新。
    • 这会递归到子目录中。将 -mindepth 1 与不带 * 的 maxdepth 1 一起使用只会打印直接目录。
    【解决方案4】:

    不创建新进程(如 find 那样)的更简单的解决方案是:

    for f in stuff/*; do
      if [ -d "$f" ]; then
         ./script.py "$f"
      fi
    done
    

    【讨论】:

      猜你喜欢
      • 2017-12-05
      • 1970-01-01
      • 2016-01-20
      • 2011-05-28
      • 2019-04-14
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多