将文件名读入数组


68

我想获取文件列表,然后将结果读入一个数组,其中每个数组元素都对应一个文件名。这可能吗?


1
对的,这是可能的。如果名称可能包含任意字符(名称中的空格和换行符会引起麻烦),则可能不建议这样做,但这是可行的。您难以理解手册的哪一部分?
乔纳森·勒夫勒

Answers:


116

请勿使用ls,这不是为此目的。使用地球。

shopt -s nullglob
array=(*)
array2=(file*)
array3=(dir/*)

nullglob如果没有匹配项,则该选项使数组为空。


谢谢,无论如何,我可以传递这些结果吗?我尝试了类似arr(* | grep“ .txt”)的方法,但是它不喜欢它。
dublintech 2012年

10
@dublintech:不需要grep,只需将字符串包括在您的glob中:array=(*.txt)array=(*foo*)
Dennis Williamson

1
您还可以将文件名附加到数组,输出文件名循环遍历它们。
Josh Habdas

25

下面将在当前目录中创建一个带有ls输出的数组arr:

arr=( $(ls) )

尽管使用的输出ls根本不安全。

ls您可以使用的更好,更安全echo *

arr=( * )

echo ${#arr[@]} # will echo number of elements in array

echo "${arr[@]}" # will dump all elements of the array

7
ls是不必要的,不应用于此目的。
丹尼斯·威廉姆森

同意,我只是想告诉您如何从某些命令输出中创建数组。但是,我编辑了我的答案以强调ls应避免输出。
anubhava 2012年

3
当不引用数组扩展时,数组的所有元素都表示为字符串,而不是数组的单个元素。未引用${arr[*]}${arr[@]}相同。
jordanm 2012年

1
有谁知道数组可以容纳的文件名/元素的最大数量是多少?
dat789 '16

2
anubhava,请删除arr=( $(ls) )行。或者,如果您想离开它,请明确添加提及,例如不要这样做,因为它已被破坏。
gniourf_gniourf '18

4

实际上,ls这不是要走的路。尝试这个:

declare -a FILELIST
for f in *; do 
    #FILELIST[length_of_FILELIST + 1]=filename
    FILELIST[${#FILELIST[@]}+1]=$(echo "$f");
done

要从数组获取文件名,请使用:

echo ${FILELIST[x]}

要从以x开头的数组中获取n个文件名,请使用:

echo ${FILELIST[@]:x:n}

有关bash数组的出色教程,请参见:http : //www.thegeekstuff.com/2010/06/bash-array-tutorial/


2
您应该遍历文件glob使用文件glob创建数组,就像我的回答一样-不能同时使用!在向数组中添加元素时,没有理由在复杂的索引表达式中使用数组的长度(一方面,如果数组稀疏,它将无法按预期工作)。array+=(element)。没有理由只使用$(echo "$f")直接进行分配。您的其中一项echo陈述中缺少左花括号。
丹尼斯·威廉姆森

2
您是否知道自己在做的事情是一种行不通的方式FILELIST = ( * )?(或者,而是FILELIST += ( * ))。为什么在地球上您使用$(echo "$f")的不仅仅是正义"$f"
gniourf_gniourf

2

在bash中,您可以创建具有路径名扩展(globbing)的文件数组,如下所示:

#!/bin/bash
SOURCE_DIR=path/to/source
files=(
   "$SOURCE_DIR"/*.tar.gz
   "$SOURCE_DIR"/*.tgz
   "$SOURCE_DIR"/**/*
)

上面的代码将创建一个名为的数组files并将N个数组元素添加到数组中,其中数组中的每个元素都对应于SOURCE_DIR结尾于.tar.gz或的项目.tgz,或者其子目录中的任何项目,并且丹尼斯在评论中指出可以进行子目录递归。

然后,您可以printf用来查看包含路径的数组的内容:

printf '%s\n' "${files[@]}" # i.e. path/to/source/filename.tar.gz

或使用参数替换来排除路径名:

printf '%s\n' "${files[@]##*/}" # i.e. filename.tgz

1
您必须先shopt -s globstar使用递归globlob(**)。
丹尼斯·威廉姆森

不适合我。并且MacOS上的默认Bash是3.2,没有globstarecho /usr/**/ | wc -c为您的输出计算某些目录名称中的字符有什么作用?在我的Mac上,在具有Bash 3.2的Sierra中或在具有Bash 4.4的情况下(globstar关闭),其输出为122。如果globstar在打开时运行Bash 4.4 ,则得到277904。后者显然是递归的,而前者不是。shopt定义了BTW,但我想您的意思是globstar(在Bash 3.2中shopt -p globstar给出了一个错误,在Bash 4.4中它显示了它是已设置还是未设置)。
丹尼斯·威廉姆森

1
hash仅适用于外部可执行文件(tryhash -t lshelp hash),不会显示任何内容,shopt因为它是内置文件,也不是globstar因为它是选项而不是可执行文件。尝试type -a shopt显示shopt来自何处以及shopt单独显示所有选项的设置。使用echo "$BASH_VERSION"以显示您当前运行的外壳的版本(如果它的击),并期待在输出ps -o tty,command,看看它实际上是/bin/bash。比较find /usr -type d | wc -lecho /usr/**/ | tr -cd " " | wc -c...
丹尼斯·威廉姆森

...如果递归遍历有效,则计数应该相当接近。我的罪名是在3800附近
丹尼斯威廉姆森

1
我可以把它留在这里 它不特定于OP的问题,但在输出文件名/路径时是一种有用的技术。
丹尼斯·威廉姆森

0

尝试这个,

path="" # could set to any absolute path
declare -a array=( "${path}"/* )

我假设您稍后会从列表中删除不需要的内容。

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.