Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Dylan,</p> <p>Your homework give me an idea to do something with my music library too, and I see than you trying do your homework alone, so here is some comments - how to make an <code>musicsort</code> command :)</p> <p>The main power of shell programming is in his ability pipelining and decomposing the job into small parts, while these small parts can easily play together.</p> <p>therefore,<br> It is not a good idea changing the column orders. See for example <code>ls -l</code>. It does not matter by what you want sort the output (e.g. ls -lt = by time, or ls -ltr = by time but reversed) the column orders remain the same. This way, you can easily pipe output from ls to another command without worrying about the column order. And if you really need changing it, here are already tools what can do it effectively. </p> <p>My 1st suggestion - don't change the output columns order only sort by them.</p> <p>Second - the header line. Print put only when really want it. (e.g. for normal output), becuse when you later want pipelining output from your brand new <code>musicsort</code> command, headers will cause much problems. So, </p> <p>my 2nd suggestion - print header only based on command argument.</p> <p>When we decomposing your problem, we get:</p> <ol> <li>need some command-line argument handling</li> <li>need set some defaults, if here are no arguments</li> <li>need find music files in your music directory</li> <li>need sort them by criteria</li> <li>need print them - in sorted order</li> </ol> <p>Skipping 1,2 for now.</p> <p>finding files in your musicdir is easy.</p> <pre><code>find "$musicdir" -type f -print </code></pre> <p>will print out all files recusively. ofc, here can be some cover images and txt lyrics so, need filter them, for example with</p> <pre><code>find "$musicdir" -type f -print | egrep -i '\.(mp3|aif*|m4p|wav|flac)$' </code></pre> <p>we have all your music files. Nicely delimited with the '/' character and in order</p> <pre><code>/path/to/musicdir/genre/artist/album/track.suffix </code></pre> <p>For the output we need remove the /path/to/musicdir/. It is easy. Here is more way, for example <code>sed</code>.</p> <pre><code>sed "s:^$musicdir/::;s:\.[^/][^/]*$::" </code></pre> <p>The above command do two things: 1.) removing the $musicdir path from your filelist, and remove any .suffix too. (like .mp3 .flac etc.). The result is:</p> <pre><code>genre/artist/album/track </code></pre> <p>Nice string, clearly separated - so sortable. For the sorting we have the <code>sort</code> command. the <code>sort</code> can sort by any field, and is possible tell him what is the field separator.<br> E.g.</p> <pre><code>sort -df -t/ -k2,2 </code></pre> <p>will sort the input separated with '/' by second field (artist). For the -df see <code>man sort</code>.</p> <p>and finally, we need read the already sorted list of files into variables and print out. (here is ofc another way too). For this bash has the <code>read</code> command. And we must tell bash what is its temporary field separator (IFS), so:</p> <pre><code>IFS=/; read genre artist album track </code></pre> <p>and because we have more lines on input need do this in cycle, while we have lines on input.</p> <p>The final script is here:</p> <pre><code>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) </code></pre> <p>As you see, the whole searching, sorting, printing is done in few lines. (parts 3, 4, 5).</p> <p>For the final, need make some argument handling. I wrote one, it is not 100% ok, but working.</p> <p>The final script what can handle some arguments, set up defaults, and do the main functionality can look like the next: (ofc, here is possible do zilion optimizations, for example combine the egrep and the sed into only one sed and etc...)</p> <pre><code>#!/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) </code></pre> <p>so for example the </p> <pre><code>$ musicsort -t -H -d . </code></pre> <p>will produce the output sorted by tracks, print header and music is in current directory</p> <pre><code>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 </code></pre> <p>As you see, the 3/4 lines are argument handling and other things. The main part is done in few lines.</p> <p>If you really need change the columns order, can be easily done, by adding few formatting lines...</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload