2011-05-27 32 views
1

我有一個腳本,它正在搜索音樂文件的目錄樹,根據特定屬性從音樂文件的完整路徑名中提取相關信息(流派,藝術家,音軌,專輯),將格式化的子串存儲爲數組中的元素,然後根據命令行上傳遞的選項(例如按照專輯排序)對數組元素進行排序。除了for循環的最後一次迭代的結果輸出似乎並沒有作爲數組中的新元素存儲之外,一切似乎都很好地工作。在查詢Bash數組的信息後,我發現數組大小沒有限制。所以我留下了深深的疑惑,爲什麼每個其他迭代的每個輸出直到最後一個迭代被存儲在數組中。如果你看下面的輸出,你可以看到最後的元素應該是軌道「苔原」。Bash:只有循環索引的最後一次迭代不被存儲爲數組的新元素

(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」的內容時,除「苔原」之外,每個軌道都以所需的格式打印(查看附件.png文件)。有沒有人有任何想法,爲什麼這可能是?這裏是我的腳本的一部分:enter image description here

#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 "" 
+0

我不知道這最後一個問題的一部分手頭解決了上述問題。你能更具體地說明最後一篇文章如何解決最後一次迭代沒有作爲數組中的新元素存儲的問題嗎?據我所知,這不是我在最後一個問題中提出的問題...... – dtg 2011-05-27 20:10:11

+2

@Dylan:弗雷德裏克的意思是,如果上一個問題的答案之一解決了它,你應該[勾選複選標記到答案](http://stackoverflow.com/faq#howtoask)。至於這個問題,這是相當長的一段代碼,我推薦先嚐試調試它,方法是在腳本的頂部放置'set -x',以便在運行時產生每行的跟蹤信息,並嘗試查找哪裏跟蹤輸出開始看起來錯誤。 – Gilles 2011-05-27 20:17:24

+0

[你已經得到](http://stackoverflow.com/questions/6116990/bash-cant-read-out-strings-with-spaces-after-looping-through-array-of-strings)幾個好建議如何用10行代碼寫你的作業......你想達到什麼目的? – jm666 2011-05-27 20:21:22

回答

3

迪倫,

你的家庭作業給我一個想法與我的音樂庫東西太多,而 我看到比你想獨自做你的功課,所以這裏有一些意見 - 如何使musicsort命令:)

shell編程的主要力量是他的能力流水線和分解作業成小部分,而這些小部分可以很容易地一起玩。

因此,
改變列順序不是一個好主意。例如參見ls -l。根據您想要對輸出進行排序(例如,ls -lt =按時間排序,或ls -ltr =按時間排序但相反),列順序保持不變。這樣,您可以輕鬆地將輸出從ls輸出到另一個命令,而無需擔心列順序。如果你真的需要改變它,這裏已經有工具可以有效地做到這一點。

我的第一個建議 - 不要改變輸出列的順序只按他們排序。

第二 - 標題行。打印只有當真正想要它。 (例如,對於正常輸出),如果稍後想要使用全新的musicsort命令進行流水線輸出,則標頭會導致很多問題。所以,

我的第二個建議 - 打印標題只基於命令參數。

當我們分解你的問題,我們得到:

  1. 需要一些命令行參數處理
  2. 需要設置一些默認值,如果在這裏沒有參數
  3. 需要找到音樂文件在你的音樂目錄
  4. 需要通過標準對它們進行排序
  5. 需要打印出來 - 在有序

現在跳過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

最後,我們需要將已排序的文件列表讀入變量並打印出來。 (這裏也是另一種方式)。對於這個bash有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行是參數處理和其他的東西。主要部分在幾行中完成。

如果你真的需要更改列順序,可以輕鬆完成,通過添加幾行格式...

+0

哇!這令人印象深刻。我有一切工作,但你的解決方案比我的更直觀。我會看看我的解決方案,並用一些建議進行修改。謝謝! – dtg 2011-05-28 16:42:22

+0

此外,apropos的頭,因爲這項任務的另一個要求是將這個實用程序與另一個在C中編程的實用程序結合使用,我只是簡單地在C中創建了頭實用程序。我想,但我需要將C代碼不知何故。我會採納你的建議併爲標題添加一個選項。謝謝!! – dtg 2011-05-28 17:10:48

相關問題