如何在 bash 中获取目录列表,然后将它们展开为命令行参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6462845/
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 do I get a list of directories in bash and then expand them as command line parameters?
提问by Charles Randall
I'm writing a bash script which needs to, for one step, get a list of directories (variable) in a target directory (which may also contain files), and then expand them out as parameters to a python script.
我正在编写一个 bash 脚本,它需要在一个目标目录(其中也可能包含文件)中获取目录(变量)列表,然后将它们作为参数扩展到 python 脚本。
Example:
例子:
/stuff/a dir/
/stuff/b other/
/stuff/c/
And I need to, within a bash script, call:
我需要在 bash 脚本中调用:
script.py "a dir/" "b other/" "c/"
or alternately, escaped spaces:
或者,转义空格:
script.py a\ dir/ b\ other/ c/
I need the script to be called exactly once for directory 'stuff'.
我需要为目录“stuff”只调用一次脚本。
Is there a straightforward way to do this kind of thing? I've been googling around and the best I've managed to figure out requires me to know how many directories there are.
有没有一种直接的方法来做这种事情?我一直在谷歌搜索,我设法找出的最好的方法要求我知道有多少目录。
回答by John Kugelman
This is a job for find.
这是一个找工作。
find /stuff -type d -exec script.py {} +
When you use -execthe curly braces {}are replaced with the names of the matching files, and +indicates the end of the command (in case you want to tell find to take additional actions). This is the ideal way to execute a command using find as it will handle file names with unusual characters (such as whitespace) correctly.
当您使用-exec大括号时,{}将替换为匹配文件的名称,并+指示命令的结束(以防您想告诉 find 采取其他操作)。这是使用 find 执行命令的理想方式,因为它将正确处理带有异常字符(例如空格)的文件名。
find is quite flexible, especially if you have the GNU version typically bundled with Linux distros.
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# 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[@]}"
' | xargs -0 script.py
In the second example notice the careful use of \0and xargs -0to use the NUL character to delimit file names. It might seem odd but this allows the command to work even if you do something really weird like use newlines \nin your directory names.
在第二个示例中,请注意小心使用\0和xargs -0使用 NUL 字符来分隔文件名。这可能看起来很奇怪,但这允许命令工作,即使您做了一些非常奇怪的事情,比如\n在目录名称中使用换行符。
Alternatively, you could do this using only shell builtins. I don't recommend this, but for educational value, here's how:
或者,您可以仅使用 shell 内置函数来执行此操作。我不推荐这个,但为了教育价值,这里是如何:
for f in stuff/*; do
if [ -d "$f" ]; then
./script.py "$f"
fi
done
回答by drwho
A simpler solution that does not create a new process (as find does) is:
不创建新进程(如 find 那样)的更简单的解决方案是:
script.py $(find /stuff/* -type d)
回答by Corey Henderson
You can use the findcommand and tell it to only print out the directories with -type d. Your command will look like this:
您可以使用find命令并告诉它只打印带有-type d的目录。您的命令将如下所示:
script.py $(find /stuff/* -type d | while read line; do echo "\"$line"\"; done)
If you're worried about spaces and other special characters, you can do this:
如果您担心空格和其他特殊字符,您可以这样做:
find /stuff/* -type d -maxdepth 1 -print0 | xargs -0 script.py
回答by Steve Prentice
This will find all the directories under /stuff, but not recursively and pass them to script.py and make sure they are passed correctly even if there are spaces in the directory names.
这将找到 /stuff 下的所有目录,但不会递归地将它们传递给 script.py 并确保即使目录名称中有空格也能正确传递它们。

