diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -14,7 +14,8 @@
 import qualified System.Environment as Env
 import System.Exit (exitFailure)
 
-import System.FilePath ((</>))
+import System.Directory (createDirectoryIfMissing)
+import System.FilePath ((</>), makeValid)
 import Text.PrettyPrint.Boxes
   (text, vcat, left, render, hsep, top, (/+/))
 
@@ -52,6 +53,50 @@
     printUsage
     exitFailure
   let args = foldr ($) defaultArgs opts
+      exportBoth matches dout = do
+        let sheets = getSheetParts matches
+            audios = getAudioParts matches
+            backingOrder = [Drums, Guitar, Keyboard, Bass, Vocal]
+            isGuitar p = elem (partToInstrument p) [Guitar, Bass]
+            (gtrs, nongtrs) = partition isGuitar [minBound .. maxBound]
+            chosenBacking = listToMaybe $ flip mapMaybe backingOrder $ \i ->
+              case getOneResult (Without i) audios of
+                Left  _  -> Nothing
+                Right fp -> Just (i, fp)
+        forM_ gtrs $ \p ->
+          case (getOneResult (Notation p) sheets, getOneResult (Tab p) sheets) of
+            (Right note, Right tab) -> let
+              parts = [note, tab]
+              systemHeight = sum $ map snd parts
+              fout = dout </> drop 4 (map toLower (show p) ++ ".pdf")
+              in do
+                putStrLn $ "Exporting notation & tab for " ++ show p
+                runSheet [note, tab] (getPageLines systemHeight args) fout
+            _ -> return ()
+        forM_ nongtrs $ \p ->
+          case getOneResult (Notation p) sheets of
+            Left  _    -> return ()
+            Right note -> let
+              fout = dout </> drop 4 (map toLower (show p) ++ ".pdf")
+              in do
+                putStrLn $ "Exporting notation for " ++ show p
+                runSheet [note] (getPageLines (snd note) args) fout
+        forM_ [minBound .. maxBound] $ \p ->
+          case getOneResult (Only p) audios of
+            Left  _  -> return ()
+            Right fp -> let
+              fout = dout </> drop 4 (map toLower (show p) ++ ".wav")
+              in do
+                putStrLn $ "Exporting audio for " ++ show p
+                runAudio [fp] [] fout
+        case chosenBacking of
+          Nothing            -> return ()
+          Just (inst, fback) -> let
+            others = [ fp | (Only p, fp) <- audios, partToInstrument p /= inst ]
+            fout = dout </> "backing.wav"
+            in do
+              putStrLn "Exporting backing audio (could take a while)"
+              runAudio [fback] others fout
   case function args of
     PrintUsage -> printUsage
     ShowDatabase -> do
@@ -81,49 +126,17 @@
           in runSheet parts (getPageLines systemHeight args) fout
     ExportAll dout -> do
       matches <- searchResultsChecked args
-      let sheets = getSheetParts matches
-          audios = getAudioParts matches
-          backingOrder = [Drums, Guitar, Keyboard, Bass, Vocal]
-          isGuitar p = elem (partToInstrument p) [Guitar, Bass]
-          (gtrs, nongtrs) = partition isGuitar [minBound .. maxBound]
-          chosenBacking = listToMaybe $ flip mapMaybe backingOrder $ \i ->
-            case getOneResult (Without i) audios of
-              Left  _  -> Nothing
-              Right fp -> Just (i, fp)
-      forM_ gtrs $ \p ->
-        case (getOneResult (Notation p) sheets, getOneResult (Tab p) sheets) of
-          (Right note, Right tab) -> let
-            parts = [note, tab]
-            systemHeight = sum $ map snd parts
-            fout = dout </> drop 4 (map toLower (show p) ++ ".pdf")
-            in do
-              putStrLn $ "Exporting notation & tab for " ++ show p
-              runSheet [note, tab] (getPageLines systemHeight args) fout
-          _ -> return ()
-      forM_ nongtrs $ \p ->
-        case getOneResult (Notation p) sheets of
-          Left  _    -> return ()
-          Right note -> let
-            fout = dout </> drop 4 (map toLower (show p) ++ ".pdf")
-            in do
-              putStrLn $ "Exporting notation for " ++ show p
-              runSheet [note] (getPageLines (snd note) args) fout
-      forM_ [minBound .. maxBound] $ \p ->
-        case getOneResult (Only p) audios of
-          Left  _  -> return ()
-          Right fp -> let
-            fout = dout </> drop 4 (map toLower (show p) ++ ".wav")
-            in do
-              putStrLn $ "Exporting audio for " ++ show p
-              runAudio [fp] [] fout
-      case chosenBacking of
-        Nothing            -> return ()
-        Just (inst, fback) -> let
-          others = [ fp | (Only p, fp) <- audios, partToInstrument p /= inst ]
-          fout = dout </> "backing.wav"
-          in do
-            putStrLn "Exporting backing audio (could take a while)"
-            runAudio [fback] others fout
+      exportBoth matches dout
+    ExportLib dout -> do
+      matches <- searchResults args
+      let titleArtists = nub [ (title info, artist info) | (_, info, _) <- matches ]
+      forM_ titleArtists $ \ta@(t, a) -> do
+        putStrLn $ "# SONG: " ++ a ++ " - " ++ t
+        let entries = filter (\(_, info, _) -> ta == (title info, artist info)) matches
+            songDir = dout </> makeValid (removeSlashes $ a ++ " - " ++ t)
+            removeSlashes = map $ \c -> case c of '/' -> '_'; '\\' -> '_'; _ -> c
+        createDirectoryIfMissing False songDir
+        exportBoth entries songDir
 
 getPageLines :: Integer -> Args -> Int
 getPageLines systemHeight args = let
@@ -236,7 +249,10 @@
     "function: export audio"
   , Opt.Option ['x'] ["export"]
     (Opt.ReqArg (\s a -> a { function = ExportAll s }) "dir")
-    "function: export all to dir"
+    "function: export song to dir"
+  , Opt.Option ['b'] ["backup"]
+    (Opt.ReqArg (\s a -> a { function = ExportLib s }) "dir")
+    "function: export library to dir"
   , Opt.Option ['c'] ["check"]
     (Opt.NoArg $ \a -> a { function = CheckPresence })
     "function: check presence of audio parts"
@@ -257,6 +273,7 @@
   | ExportSheet FilePath
   | ExportAudio FilePath
   | ExportAll   FilePath
+  | ExportLib   FilePath
   | CheckPresence
   deriving (Eq, Ord, Show, Read)
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
 It should go without saying, but please do not distribute content from songs you have purchased --
 it is for your use only!
 
-Download the latest Windows/Mac binaries from the [releases page](https://github.com/mtolly/jammittools/releases).
+Download the latest Windows/Mac/Linux binaries from the [releases page](https://github.com/mtolly/jammittools/releases).
 
 [Jammit]: https://www.jammit.com/
 
@@ -33,6 +33,10 @@
     # Do a "dry run" of audio extraction, which checks if the parts exist
     # but does not do any conversion. Exits with a non-zero code if any
     # part does not exist.
+
+    jammittools -b dir
+    # Full library backup: runs -x for each song in your library.
+    # Each song is extracted to its own folder within "dir".
 
 Other lesser-used flags:
 
diff --git a/jammittools.cabal b/jammittools.cabal
--- a/jammittools.cabal
+++ b/jammittools.cabal
@@ -1,5 +1,5 @@
 Name:               jammittools
-Version:            0.5.0.3
+Version:            0.5.1
 Synopsis:           Export sheet music and audio from Windows/Mac app Jammit
 Description:
 
@@ -61,7 +61,7 @@
     , directory     >= 1.2.0.1 && < 1.3
     , filepath      >= 1.3.0.1 && < 1.5
     , boxes         >= 0.1.3   && < 0.2
-    , jammittools   == 0.5.0.3
+    , jammittools   == 0.5.1
   ghc-options:      -Wall -O2
 
 source-repository head
