如何在Linux Bash中将ls分配给阵列?


Answers:


109

就是这个

array=($(ls -d */))

编辑:请参阅戈登·戴维森(Gordon Davisson)的解决方案,以获得更一般的答案(即,如果文件名包含特殊字符)。这个答案仅仅是语法校正。


14
如果目录名称包含空格,这将无法正常工作。
chepner 2013年

1
为了解决空格或特殊字符的问题,请先声明不带任何值的数组,然后使用内置函数ARR+=('$(ls -d */)')来编辑数组中的元素,同时使用单引号处理特殊字符,以在其中添加或删除元素数组。单引号保留字面字符,并消除了在目录名称中使用转义符进行处理的任何需要。
Yokai

@Yokai您的建议听起来很棒,但在Ubuntu 16.04或MacO上对我不起作用。Bash像这样扩展单引号之间的代码:declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')仅返回$(ls -d $INPUT_DIR/*)
Agile Bean

1
我的错。那应该是双引号,以便可以扩展命令替换。ARR+=("$(ls -d */)")应该管用。如果不是,就让我知道。
Yokai

2
@Yokai,总共只添加一个元素(其中包含一串换行符),而不是每个目录一个元素。
查尔斯·达菲,

76

只要有可能,就应该避免解析输出ls(请参阅Greg关于该主题的Wiki)。基本上,ls如果任何文件名中都有有趣的字符,的输出将是模糊的。通常也浪费时间。在这种情况下,执行时ls -d */,shell将扩展*/为一个子目录列表(这已经完全是您想要的),并将该列表作为参数传递给ls -d,然后对每个子目录进行查看,并说“是的,那是一个目录正确”并打印出来(格式不一致,有时甚至模棱两可)。该ls命令没有做任何有用的事情!

好吧,这是一件有用的事情:如果没有子目录,那么*/将保留原样,ls将查找名为“ *”的子目录,找不到它,并打印一条不存在的错误消息( stderr),而不打印“ * /”(至stdout)。

创建子目录名称数组的更干净的方法是使用glob(*/而不将其传递给ls。但是,如果没有实际的子目录,为了避免在数组中放置“ * /”,您应该首先设置nullglob(同样,请参见Greg的wiki):

shopt -s nullglob
array=(*/)
shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything later
echo "${array[@]}"  # Note double-quotes to avoid extra parsing of funny characters in filenames

如果要在没有子目录的情况下打印错误消息,最好自己动手做:

if (( ${#array[@]} == 0 )); then
    echo "No subdirectories found" >&2
fi

2
感谢您的评论,即使未将其标记为答案,它也提供了很多信息,我对此表示赞赏。
杰克H

如果您不希望/dir名称怎么办?
shinzou

greg Wiki中概述的问题/问题并非仅凭条件构造就无法轻易解决的问题。ls是一个简单的命令。它的输出是字符串。Bash在解析字符串方面非常擅长。正确的正则表达式是安全解析ls输出所必需的。
Yokai

@Yokai不同版本的ls文件名使用文件名中的有趣/非打印字符来执行不同的操作,因此没有一致的方法将其输出解析为文件名列表。就像我说的,它实际上并没有做任何有用的事情:如果您正确解析的输出ls -d */,那么最终会得到与您直接从中得到的完全一样的东西*/(除非没有匹配项,并且很容易检查)。
戈登·戴维森

总结一下:A lazy sysadmin is a good sysadmin.也许我自己的ls解析特定于我所拥有的版本,或者我曾经使用过,但是到目前为止,它们在我对其进行测试的linux发行版上都没有问题。我只能凭经验说话。
Yokai

7

这将逐行打印这些目录中的文件。

array=(ww/* ee/* qq/*)
printf "%s\n" "${array[@]}"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.