while read iPosted 8 July 2008 in bash, programming, and technology
I have finally finished backing up all of my data. It took four DVDs, but I finally did it. It would have required several more had I not filtered my music files for backup, however. In particular, the only music that I truly had to save were the songs I've purchased on iTunes and eMusic...but I've got many, many ripped CDs as well, so how can I separate my .m4a's and .mp3's (the proprietary formats that my purchases are in) from my .ogg's and .flac's (the open formats I chose to rip my CDs to)?
Simple! I'll just whip out a shell script that takes all of the files that aren't ripped in open formats, and BZZT WRONG. You see, I usually write for loops at the command line. They're fast and easy, but when looping through something that has spaces in it (such as my directories and filenames), there are going to be errors. Lots of errors. Given a directory with two files, named "a 1.mp3" and "b 2.mp3", the following happens:
$ for i in $(ls); do echo $i; done a 1.mp3 b 2.mp3
What I really need is a way to get the following output:
$ <some awesome command> a 1.mp3 b 2.mp3
A long time ago I consulted with Allan, and we lit upon the solution: "while read i". As long as data is being piped in, "read" will take in another line, "while" will evaluate true, and our loop will continue churning. Unfortunately, I always forget about "read", which is what prompted this entry. So the "some awesome command" above is actually just:
$ ls | while read i; do echo "$i"; done
In truth, though, the full command was similar to the following (but without all the formatting):
$ find /opt/Music/ | grep -ve "\.ogg$" | while read i; do if [ ! -d "$i" ]; then echo "$i" fi done
In plain English, that says "List everything in the Music directory, strip out all of the Ogg files and, if it's not a directory, print it out".
And now may I never forget "read" again.