Industry guru Dave Taylor answers free tech support questions about a wide variety of business and technical topics, including blogging, Google AdSense, MySpace, Sony PSP, Apple iPod, Mp3 players, management, Linux, SEO, Mac OS X, Facebook, Twitter, LinkedIn and Microsoft Windows.

Can I list my iTunes Library by number of albums?

I've spent a lot of time poking around with my extensive iTunes database and had lots of fun figuring out different ways to address my needs with a fully digitized music collection. When a reader asked whether there was a way to just list those artists in her iTunes collection for whom she had more than one album, I thought "ah, this sounds up my alley", and so it is.

Dave's Answer:

As with all my solutions, this involves starting up by opening up the Terminal application (Applications -> Utilities) and typing the following directly on the command line or into a shell script. In this case, it's really so easy that I suggest it might just be a nice alias.

The key to answering this problem is to recognize that iTunes stores its library in the form Artist/Album/Track, as directories, subdirectories and files. Want to see what artists you have in your library, for example? Just use:

$ cd ~/Music/iTunes/iTunes\ Music
$ ls
My library is rather extensive, about 300 albums, so I'll skip showing you this output. :-)

Knowing that, the find command offers the solution to this question: with find you can use the little-known mindepth and maxdepth parameters to specify exactly how far into the directory tree the program should travel. To list artists and albums, but not song names, you can use the following (assuming you've already moved into your 'iTunes Music' folder):

$ find . -mindepth 2 -maxdepth 2 -print
./Al Jarreau/All I Got
./Al Jarreau/Heaven And Earth
./Alan Parsons Project/Best Of The Alan Parsons Project
./Alan Parsons Project/Eve
./Alan Parsons Project/Eye In The Sky
./Alan Parsons Project/I Robot
 etc, etc etc etc
That's getting us there. Now what we need to do is actually just isolate the artist names, then count how many artist names appear more than once in the output. Make sense?

To isolate the artist names, notice that there's a regular pattern here, of somethingslashsomethingslashsomething, which means that we can slice each line of output to get what we want by using the slash as a delimiter to the useful application cut. It's the second field we'd like to see here (the first is just the '.', the shorthand for 'this directory' in the output), so here's the command needed:

$ find . -mindepth 2 -maxdepth 2 -print | cut -d/ -f2
Al Jarreau
Al Jarreau
Alan Parsons Project
Alan Parsons Project
Alan Parsons Project
etc etc
Almost there.

All that's left is to asceratain how often each artist name appears, and that can be done with the useful uniq (say "unique") command's -c flag, which does exactly what we see:

$ find . -mindepth 2 -maxdepth 2 -print | cut -d/ -f2 | uniq -c
   2 Al Jarreau
   9 Alan Parsons Project
   2 Andreas Vollenweider
   2 Bee Gees
   1 Bill Whelan
   1 Billie Holiday
   1 Billy Joe Walker, Jr_
   6 Billy Joel
   2 Bobby McFerrin
  11 Bruce Hornsby
   5 Bruce Springsteen
etc etc
We're soooo close now. Just two steps left: remove those that only have one occurrence (like Bill Whelan and Billie Holiday), then sort the remaining data from largest to smallest number of matches. The former can be accomplished by using a specialized version of grep that uses a regular expression (we don't want to just screen anything out that has '1' because it'll match '11' too and Bruce Hornsby will vanish. Not good). To sort numerically, we'll use sort and add the -n flag for numeric, and the -r reverse flag to sort largest to smallest. Add it all up and here's the final output:
$ find . -mindepth 2 -maxdepth 2 -print | cut -d/ -f2 | \
uniq -c | grep -vE '( 1 )' | sort -rn
  12 Ella Fitzgerald
  11 Bruce Hornsby
   9 Kate Bush
   9 Alan Parsons Project
   7 Kenny Loggins
   6 Billy Joel
   5 Sting
   5 Bruce Springsteen
   4 Paul Simon
   4 Don Henley
   3 The Moody Blues
   3 Robert Johnson
   3 Phil Collins
   3 Pat Metheny Group
   3 James Taylor
   3 Genesis
   3 Dire Straits
   2 Spyro Gyra
   2 Huey Lewis & The News
   2 Bobby McFerrin
   2 Bee Gees
   2 Andreas Vollenweider
   2 Al Jarreau
That's the solution and, as I said in the beginning, it's not really even enough to make a good shell script. Instead, just prefix the command with "alias favorites=" and surround the entire command with quotes and we'll be able to get this information at any time by simply typing favorites on the Terminal command line.

If you've found this interesting, by the way, you'll doubtless love the best-selling Wicked Cool Shell Scripts, where I show over 100 different scripts in just this manner, many specifically for Mac OS X.



Help others find this article at Del.icio.us, Digg, Netscape, Reddit, and Simpy.

Subscribe!

Never miss another useful Q&A article again! Subscribe to AskDaveTaylor with Google Reader.

Comments

I have a slight correction to your script. I use

find "/Users/Shared/iTunes/iTunes Music" -mindepth 2 -maxdepth 2 -print | grep -v .DS_Store | \
cut -d/ -f6 | uniq -c | grep -v " 1 " | sort -rn

The important changes:
1) I give the full pathname to find, so you don't need to "cd" to your iTunes folder.
2) I filter out the .DS_Store files (which pop-up like weeds) and would give you incorrect counts.
3) Since I use the full path, I use a different -f value for cut
4) I use a simpler grep -v " 1 " (that's -v "[space][space]1[space]") instead of -vE "( 1 )". This is also makes it more unlikely to filter out Artists with a 1 in their name (because of the double space).

Posted by: John Wenn at November 19, 2004 4:17 AM

Actually, I didn't want to hardcode the directory because it's really better form to find out where the music library is stored by looking in the configuration XML file, which can be done thusly:

itunehome="$HOME/Music/iTunes"
ituneconfig="$itunehome/iTunes Music Library.xml"

musiclib="/$(grep '>Music Folder<' "$ituneconfig" | cut -d/ -f5- | \
cut -d\< -f1 | sed 's/%20/ /g')"

With that, you would want to use the "cd" to get to that directory (even if it's ~/Music/iTunes/iTunes Music/ most of the time).

In terms of filtering out .DS_Store, it's not a problem because the only time that would affect the output was if there was more than one file called ".DS_Store" in a given artist's directory (remember, we sort by artist before we calculate the number of subdirectories). Consider:

$ find $iTunesHome -name ".DS_Store" -print
./.DS_Store
./Bruce Springsteen/.DS_Store
./Bruce Springsteen/The Essential/.DS_Store
./Ella Fitzgerald/.DS_Store
./Joe Jackson/.DS_Store
./Kate Bush/.DS_Store
./The Beatles/.DS_Store

I can't have two of them in a single artist's directory (since you can't have two files with the same name in a single directory), so there's no way that they'd survive the pipe I built.

And, finally, in terms of the masking pattern to eliminate those artists with only a single album, I agree that your pattern is better than mine.

Thanks for your great suggestions!

Posted by: Dave Taylor at November 19, 2004 4:38 AM

You still get a count that is wrong. In your example, Bruce Springsteen, Ella Fitzgerald, Joe Jackson, Kate Bush & The Beatles will all have counts 1 too large. Do a "ls The\ Beatles" and compare the number of subdirectories with the count your script gives.

This is because you aren't counting subdirectories. You are counting items in the artist directory. If you were to say

find . -mindepth 2 -maxdepth 2 -type d -print

Then you would be counting subdirectories. The -d flag is key. This is probably a better fix then explictly filtering out .DS_Store files.

/John

Posted by: John Wenn at November 20, 2004 10:49 PM

Oops. I meant

the -type d flag is key

Posted by: John Wenn at November 20, 2004 10:51 PM

You're right: Those directories that have a .DS_Store file do throw off the count on this script, but it's easily fixed, as you say, by just specifying that "find" should only match directories. Another solution could be to use a "| grep -v .DS_Store" within the pipeline, but constraining find to directories is undoubtedly the smarter solution.

Thanks for the eagle eye on this!

Posted by: Dave Taylor at November 21, 2004 1:20 AM

One last fiddle, I promise.

The remaining thing that bothered me about the script was the sort order. It was
*) Largest number first (good)
*) With the same number, artist in reverse order (bad)
*) Lower case artists (e.g. "k.d. lang") are at the end (bad)

Changing the sort to

sort +0rn +1f

corrects all the problems.

/John

Posted by: John Wenn at November 21, 2004 5:16 AM

Alright, now you're getting into personal preferences in terms of how sophisticated you want things to be versus just demonstrating the basic concept, John. Maybe you're being a bit of a, um, perfectionist here? :-)

Besides, you'll notice that I don't have any albums from artists who don't know what the SHIFT key is for on their keyboards!

Posted by: Dave Taylor at November 21, 2004 5:36 AM

Sweet writeup, thanks! ((is it against the rules to go back and edit the below comments into the above text?))

Anyway, I was looking for a way to figure out how many open files each process had open--I knew lsof, but I didn't know that uniq had a -c option. Thanks for randomly having the answer I needed!

I don't know how platform specific lsof's layout is, but --

lsof | tr -s ' ' ' ' | cut -d ' ' -f 2 | uniq -c | sort -n +0

(for that matter, I either didn't know or had long ago forgotten sort could take multiple fields)

Posted by: kaolin fire at January 9, 2006 10:59 PM

the itunes shell command is neat but is there a way to get a command prompt to do that in windows?

Posted by: william at February 11, 2007 5:19 PM

I can't get that command to work.

Posted by: Bruce Friedman at April 14, 2008 10:00 AM

I have a lot to say, but ...
Starbucks coffee cup I have a lot to say, and questions of my own for that matter, but most of all I'd like to say thank you for all your efforts on this Web site by buying you a chai!

I do have a comment, now that you mention it!









Remember personal info?


Please note that I will never send you any unsolicited commercial email. Ever.

While I'm at it, please note that by submitting a question or comment you're agreeing to my terms of service, which are: you relinquish any subsequent rights of ownership to your material by submitting it on this site.









Search
Find just the answers you seek from among our 1700+ free tech support articles by using our Lijit search engine.


Help!





Subscribe to
Ask Dave Taylor!

Add to Google Reader
Add to My Yahoo!
Subscribe in NewsGator Online

RDF   XML

Free Updates!
Sign up and get free weekly updates and special offers on books, seminars, workshops and more.


Recent Entries
Join the List!
Join my author info mailing list, where you'll learn about my upcoming books, speaking gigs, and more!


Book Links
© 2002 - 2008 by Dave Taylor. All Rights Reserved.

Note: This web site is for the purpose of disseminating information for educational purposes, free of charge, for the benefit of all visitors. We take great care to provide quality information. However, we do not guarantee, and accept no legal liability whatsoever arising from or connected to, the accuracy, reliability, currency or completeness of any material contained on this web site or on any linked site.

[whiteboard marker tray]