排序元素读入数组

时间:2015-02-02 19:33:06

标签: arrays bash sorting

在将find结果读入数组时,我希望它们同时排序(mp3,所以按轨道号,这是文件名的第一部分),并认为这样的事情应该做的伎俩:

mp3s=()
while read -r -d $'\0'; do
    mp3s+=("$REPLY")
done < <(sort <(find "$mp3Dir" -type f -name '*.mp3' -print0))

但数组中的元素永远不会正确排序(文件名的第一部分是mp3轨道号:01 _...,02 _...,03 _...等)

虽然以下内容完成了工作,但似乎不必要的尴尬:

mp3s=()
while read -r -d $'\0'; do
    mp3s+=("$REPLY")
done < <(find "$mp3Dir" -type f -name '*.mp3' -print0)

mp3s=( $(for f in "${mp3s[@]}" ; do
    echo "$f"
done | sort) )

必须有一种更简化的方法来完成这项工作,与我在第一个例子中的想法类似,不是吗?我已尝试在sort命令的两侧阅读find,使用其众多选项进行排序(-n,-d等),但没有任何运气(到目前为止)。

那么,在最初填充数组时,是否有更有效的方法来合并sort命令?

2 个答案:

答案 0 :(得分:4)

默认情况下,sort采用换行符分隔的记录。但是,对find的调用指定了空分隔输出。解决方案是将-z标志添加到sort。这告诉sort期望nul分离的输入并产生nul分离的输出。因此,请尝试:

mp3s=()
while read -r -d $'\0'; do
    mp3s+=("$REPLY")
done < <(sort -z <(find "$mp3Dir" -type f -name '*.mp3' -print0))

实施例

假设我们有这些mp3文件:

$ find "." -type f -name '*.mp3' -print0
./music1/d b2.mp3./music1/a b1.mp3./music1/a b2.mp3./music1/d b1.mp3./music1/a b3.mp3./music1/d b3.mp3

首先,试试sort

$ sort <(find "." -type f -name '*.mp3' -print0)
./music1/d b2.mp3./music1/a b1.mp3./music1/a b2.mp3./music1/d b1.mp3./music1/a b3.mp3./music1/d b3.mp3

文件仍然无序。

现在,试试sort -z

$ sort -z <(find "." -type f -name '*.mp3' -print0)
./music1/a b1.mp3./music1/a b2.mp3./music1/a b3.mp3./music1/d b1.mp3./music1/d b2.mp3./music1/d b3.mp3

这些文件现在已按顺序排列。

答案 1 :(得分:4)

在内部进行bash排序的一种方法是使用关联数组并将数据放入键中,而不是值。

declare -A mp3s=()
while IFS= read -r -d ''; do
    mp3s[$REPLY]=1
done < <(find "$mp3Dir" -type f -name '*.mp3' -print0)

...然后,迭代值:

for mp3 in "${!mp3s[@]}"; do
  printf '%q\n' "$mp3"
done

由于关联数组是bash 4.0中添加的一项功能,请注意3.2中没有此功能(在某些圈子中仍在使用,特别是MacOS)。