将读入的元素排序并存入数组中

3

读取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命令的各种选项(-n,-d等)来排序find命令的结果,但是目前还没有成功。

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


1
如果您不希望“read”通过修剪文件名中的尾随空格来修改数据,则还需要清除“IFS”。 - Charles Duffy
1
此外,$'\0''' 完全相同,因为bash使用NUL分隔的字符串,因此无法在字符串中存储NUL。这正是在-d中起作用的原因--零长度的NUL分隔字符串的第一个字符当然是其NUL分隔符。就个人而言,我认为$'\0'语法是不好的实践,因为它可能会让人们相信bash可以在字符串内部存储NUL,这是错误的,而不是只使用IFS= read -r -d '' - Charles Duffy
如果你不相信它是假的,那么把$'\0foo'放入一个字符串中,然后尝试提取foo - Charles Duffy
2个回答

4

默认情况下,sort 假定记录之间使用换行符分隔。然而,调用 find 指定了以 null 分隔的输出。解决方法是在 sort 中添加 -z 标志。这告诉 sort 期望以 null 分隔的输入并生成以 null 分隔的输出。因此,请尝试:

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

文件现在已经排好序了。

使用进程替换而不是管道连接findsort之间是否有任何理由? - Charles Duffy
哦,我明白了——原来是楼主最初就是这样做的。 - Charles Duffy

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中添加的功能,因此请注意,在某些领域(尤其是MacOS),仍在使用版本3.2,因此该功能不可用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接