Bash:仅循环索引的最后一次迭代不存储为数组的新元素

| 我有一个脚本在目录树中搜索音乐文件,根据特定属性(流派,艺术家,曲目,专辑)从音乐文件的完整路径名中提取相关信息,并将格式化后的子字符串作为元素存储在数组中,然后根据在命令行中传递的选项对数组的元素进行排序(例如,按相册排序)。一切似乎都运行良好,除了for循环最后一次迭代的结果输出似乎没有作为新元素存储在数组中。在查找有关Bash阵列的信息后,我发现阵列大小没有限制。因此,我不停地思考为什么每一次迭代的每个输出直到最后一次都存储在数组中。如果查看下面的输出,可以看到最后一个元素应该是轨道“ Tundra \”。
(more output above ...)

-->./Hip-Hop/OutKast/Stankonia/Toilet Tisha.aif<-- 
GENRE:
Hip-Hop
ARTIST:
OutKast
ALBUM:
Stankonia
TITLE:
Toilet Tisha

-->./Electronic/Squarepusher/Hard Normal Daddy/Cooper\'s World.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Hard Normal Daddy
TITLE:
Cooper\'s World

-->./Electronic/Squarepusher/Hard Normal Daddy/Papalon.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Hard Normal Daddy
TITLE:
Papalon

-->./Electronic/Squarepusher/Hard Normal Daddy/Vic Acid.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Hard Normal Daddy
TITLE:
Vic Acid

-->./Electronic/Squarepusher/Go Plastic/Go! Spastic.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Go Plastic
TITLE:
Go! Spastic

-->./Electronic/Squarepusher/Go Plastic/Greenways Trajectory.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Go Plastic
TITLE:
Greenways Trajectory

-->./Electronic/Squarepusher/Go Plastic/My Red Hot Car.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Go Plastic
TITLE:
My Red Hot Car

-->./Electronic/Squarepusher/Feed Me Weird Things/Kodack.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Feed Me Weird Things
TITLE:
Kodack

-->./Electronic/Squarepusher/Feed Me Weird Things/North Circular.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Feed Me Weird Things
TITLE:
North Circular

-->./Electronic/Squarepusher/Feed Me Weird Things/Tundra.aif<--
GENRE:
Electronic
ARTIST:
Squarepusher
ALBUM:
Feed Me Weird Things
TITLE:
Tundra
如您所见,DEBUG部分中的最后一个迭代应该是标题\“ Tundra \”。但是,当我显示数组\“ track_list \”的内容时,除\“ Tundra \”以外的所有轨道都以所需的格式打印(请参阅附加的.png文件)。有谁知道为什么会这样吗?这是我脚本的一部分:
#more code above ...

#create arrays
declare -a track_list
declare -a directory_contents


#populate directory with files
cd $directory
directory_contents=$(find .  -mindepth 1 -type f)
cd ..


IFS=$\'\\n\'


#store each file of directory in track_list
for music_file in ${directory_contents[*]}; do
    if [ -n \"$DEBUG\" ] ; then echo \"-->$music_file<--\"; fi

    this_genre=$(echo $music_file | awk -F\"/\" \'{print $2}\')
    this_artist=$(echo $music_file | awk -F\"/\" \'{print $3}\')
    this_album=$(echo $music_file | awk -F\"/\" \'{print $4}\')
    this_title=$(echo $music_file | awk -F\"/\" \'{print $5}\' |\\
        awk -F\".aif\" \'{print $1}\' || awk -F\".mp3\" \'{print $1}\' ||\\
        awk -F\".wav\" \'{print $1}\' || awk -F\".flac\" \'{print $1}\' \\
        || awk -F\".m4a\" \'{print $1}\')

    function artist_list
    {
    track=$(printf \"%-20s\\t\\t%-30s\\t\\t%-30s\\t\\t%-10s\\n\"\\
            \"$this_artist\" \"$this_title\" \"$this_album\" \"$this_genre\")
    track_list=(\"${track_list[*]}\" $track)
    }

    if [[ $genre = \"true\" ]] ; then
    track=$(printf \"%-10s\\t\\t%-20s\\t\\t%-30s\\t\\t%-30s\\n\"\\
            \"$this_genre\" \"$this_artist\" \"$this_title\" \"$this_album\")
    track_list=(\"${track_list[*]}\" $track)
    elif [[ $artist = \"true\" ]] ; then
    artist_list
    elif [[ $album = \"true\" ]] ; then
    track=$(printf \"%-30s\\t\\t%-20s\\t\\t%-30s\\t\\t%-10s\\n\"\\
            \"$this_album\" \"$this_artist\" \"$this_title\" \"$this_genre\")
    track_list=(\"${track_list[*]}\" $track)
    elif [[ $title = \"true\" ]] ; then
    track=$(printf \"%-30s\\t\\t%-20s\\t\\t%-30s\\t\\t%-10s\\n\"\\
            \"$this_title\" \"$this_artist\" \"$this_album\" \"$this_genre\")
    track_list=(\"${track_list[*]}\" $track)
    else
    artist_list
    fi

    if [ -n \"$DEBUG\" ]; then
    echo \"GENRE:\"
    echo $this_genre
    echo \"ARTIST:\"
    echo $this_artist
    echo \"ALBUM:\"
        echo $this_album
    echo \"TITLE:\"
    echo $this_title
    echo \"\"
    fi
done


unset IFS


if [[ $genre = \"true\" ]] ; then
    ./mulib g
elif [[ $artist = \"true\" ]] ; then
    ./mulib a
elif [[ $album = \"true\" ]] ; then
    ./mulib m
elif [[ $title = \"true\" ]] ; then
    ./mulib t
else
    ./mulib
fi

echo \"$track_list\" | sort
echo \"\"
    
已邀请:
迪伦 您的作业使我有了一个使用音乐库做点什么的主意,并且 我看到比您尝试独自做作业要多,因此这里有一些评论-如何制作
musicsort
命令:) Shell编程的主要力量在于将流水线工作分解成小部分的能力,而这些小部分可以轻松地一起玩。 因此, 更改列顺序不是一个好主意。例如参见
ls -l
。列的顺序保持不变,无论您要对输出进行什么排序都无关紧要(例如ls -lt =按时间或ls -ltr =按时间但取反)。这样,您可以轻松地将ls的输出通过管道传递给另一个命令,而不必担心列顺序。而且,如果您确实需要更改它,那么这里已经有一些工具可以有效地进行更改。 我的第一个建议-不要更改输出列的顺序,仅按它们排序。 第二-标头行。仅在真正需要时才打印。 (例如,用于正常输出),因为当您以后想要从全新的
musicsort
命令流水线化输出时,标头会带来很多问题。所以, 我的第二个建议-仅根据命令参数打印标题。 当我们分解您的问题时,我们得到: 需要一些命令行参数处理 如果没有参数,则需要设置一些默认值 需要在您的音乐目录中找到音乐文件 需要按条件对它们进行排序 需要打印它们-排序 现在跳过1,2。 在musicdir中查找文件很容易。
find \"$musicdir\" -type f -print
将删除所有文件。 ofc,这里可能是一些封面图片和txt歌词,因此需要对其进行过滤,例如
find \"$musicdir\" -type f -print | egrep -i \'\\.(mp3|aif*|m4p|wav|flac)$\'
我们拥有您所有的音乐文件。很好地用\'/ \'字符定界
/path/to/musicdir/genre/artist/album/track.suffix
对于输出,我们需要删除/ path / to / musicdir /。这很容易。这是更多方法,例如
sed
sed \"s:^$musicdir/::;s:\\.[^/][^/]*$::\"
上面的命令有两件事:1.)从文件列表中删除$ musicdir路径,并删除所有.suffix。 (如.mp3 .flac等)。结果是:
genre/artist/album/track
细腻的细绳,清晰分开-易于分类。对于排序,我们使用
sort
命令。
sort
可以按任何字段排序,并且可以告诉他什么是字段分隔符。 例如。
sort -df -t/ -k2,2
会以第二个字段(艺术家)对用\'/ \'分隔的输入进行排序。有关-df的信息,请参见
man sort
。 最后,我们需要将已经排序的文件列表读入变量并打印出来。 (这也是off的另一种方式)。为此,请执行
read
命令。而且我们必须告诉bash它的临时字段分隔符(IFS)是什么,所以:
IFS=/; read genre artist album track
并且因为我们有更多的输入行需要循环执行此操作,而我们有输入行。 最终的脚本在这里:
musicdir=\".\"
FORMAT=\"%-20s%-35s%-35s%-35s\\n\"
sortby=2 #for this example - artist

find \"$musicdir\" -type f -print |\\
egrep -i \'\\.(aif*|mp3|flac|m4a|wav)$\' |\\
sed \"s:^$musicdir/::;s:\\.[^/][^/]*$::\" |\\
sort -t/ -k$sortby,$sortby | (
IFS=/; while read genre artist album track
do
        printf \"$FORMAT\" $genre $artist $album $track
done)
如您所见,整个搜索,排序和打印只需几行。 (第3、4、5部分)。 最后,需要进行一些参数处理。我写了一篇,那不是100%可以,但可以。 最终的脚本可以处理一些参数,设置默认值以及完成主要功能,如下所示:(ofc,这里可以进行zilion优化,例如将egrep和sed合并为一个sed等。 )
#!/bin/bash
#argument handling - not 100% correct, but working...
while getopts \"hHgaltd:\" arg
do
case \"$arg\" in
    g) sortby=1;;
    a) sortby=2;;
    l) sortby=3;;
    t) sortby=4;;
    d) musicdir=$OPTARG;;
    H) header=y;;
    h|?)    echo \"Usage: $0 [-d music_dir] [-g|-a|-l|-t] [-H]\";
        echo \' -d music_dir = path to your music directory (default \".\")\'
        echo \' -g|-a|-l|-t = for sorting by Genre/Artist/aLbum/Track (default \"-a\")\'
        echo \' -H print header (default no)\'
        exit 1;;
esac
done

#defaults
sortby=${sortby:=2};
musicdir=${musicdir:=.}
FORMAT=\"%-20s%-35s%-35s%-35s\\n\"

#header only if want one
if [[ $header == \"y\" ]]
then
    printf \"$FORMAT\" genre artist album track
    printf -v line \'%*s\' 125; echo ${line// /-}
fi

#the main part - search, sort, read into variables, print
find \"$musicdir\" -type f -print |\\
egrep -i \'\\.(aif*|mp3|flac|m4a|wav)$\' |\\
sed \"s:^$musicdir/::;s:\\.[^/][^/]*$::\" |\\
sort -t/ -k$sortby,$sortby | (
IFS=/; while read genre artist album track
do
    printf \"$FORMAT\" $genre $artist $album $track
done)
所以例如
$ musicsort -t -H -d .
将产生按曲目,打印标题和音乐排序的输出,位于当前目录中
genre               artist                             album                              track                              
-----------------------------------------------------------------------------------------------------------------------------
Electronic          Squarepusher                       Hard Normal Daddy                  Cooper\'s World                     
Electronic          Squarepusher                       Go Plastic                         Go! Spastic                        
Electronic          Squarepusher                       Go Plastic                         Greenways Trajectory               
Electronic          Squarepusher                       Feed Me Weird Things               Kodack                             
Electronic          Squarepusher                       Go Plastic                         My Red Hot Car                     
Electronic          Squarepusher                       Feed Me Weird Things               North Circular                     
Electronic          Squarepusher                       Hard Normal Daddy                  Papalon                            
Hip-Hop             OutKast                            Stankonia                          Toilet Tisha                       
Electronic          Squarepusher                       Feed Me Weird Things               Tundra                             
Electronic          Squarepusher                       Hard Normal Daddy                  Vic Acid        
如您所见,3/4行是参数处理等。主要部分完成了几行。 如果您确实需要更改列顺序,只需添加几行格式即可轻松完成...     

要回复问题请先登录注册