How To: Compress a Directory of Files into Individual Archivesr3dux | April 16, 2009
I’ve got a stack of files all thrown together in the same directory, and I wanted them compressed – simple enough, eh? Only thing is I wanted each file compressed to its own archive, so I can see at a glance what’s there, and if for some reason an archive gets corrupted, it’s just one file lost and I can replace it instead of having to dick around repairing corrupted “blob” archives that contain the entire bunch of files. And I want to be able to specify all files with a given file extension to compress.
Although I wouldn’t be surprised if you could do this in 4 lines of Perl, I don’t know flippin’ Perl (yet), so I wrote a bash script to do the job.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
# # Purpose: Script to compress all files of given extension to individual archives using 7z # Usage : zipeach.sh <extension-without-prefix-dot> i.e zipeach.sh n64 # Author : r3dux # Date : 16/04/2009 # #!/bin/bash count=0 # File counter got7z=$(which 7z) # Use "which" to check if there's a copy of 7z on the system # If there's no copy of 7z - we're not going to be doing much compressing... Exit stage left. if [ "$got7z" = "" ]; then echo "No copy of 7z found on system! Try running: sudo apt-get install p7zip-full" exit 0 fi # If we have 7z, and have been given a file extension parameter... if test "$1"; then # Stop the script from entering an infinite loop should user mistakenly enter 7z as filetype to compress... if [ $1 = "7z" ]; then echo "Recursion neatly sidestepped - no 7z filetypes ya scurvy seadog! =P" exit 0 fi echo "Starting Zipeach..." # For each file with the given extension in the current directory... for file in ./*.$1; do # If a file exists with given extension... if [ -e "$file" ]; then # Compress the file with maximum compression (-mx9) and use multiple threads for multiCPU machines (-mmt) # NOTE: Remove -mmt flag to run this on a single CPU box... 7z a -mx9 -mmt "$file".7z "$file" # Increment our file counter let count+=1 else # If no file of required extension has been found then notify user and quit echo "No files of extension .$1 found in current directory!" exit 0 fi # End of if file exists condition done # End of for each file loop # Exit when all files compressed echo # Cheap blank line =P echo "Zipeach completed. $count files of extension .$1 found and compressed." exit 0 else # No extension parameter given? No worky... echo echo 'Please run the script with an extension to compress i.e. "zipeach.sh n64" to compress each .n64 file into its own 7z archive.' exit 0 fi
Bash, as it turns out, is a fiddly, finicky beast in that you really have to think about what the command-line will see under different circumstances and enclose variables in inverted commas or not in very precise ways (see this article to understand what I mean). All that if / fi stuff too… very odd.
To use the script, copy and paste it into a text file (in my case I’ve called it zipeach.sh), save it, make the file executable using chmod +x zipeach.sh and move it to /usr/bin or something so it’s in your path using sudo mv ./zipeach.sh /usr/bin/ – then run it inside any directory you want to zip files to individual archives by calling it with zipeach.sh nds (for example) to compress all the .nds (Nintendo DS roms) in a folder into individual archives. Or use this link
Anyway, job done – suggestions? improvements? props? death-threats? Let me know below!