Back in the early 1980s I used PKZIP in DOS to archive files to conserve disk space. I am finding that I have this need now. Can anyone assist me with this?
Requirements:
1 – select a folder from Finder
2 – store the folder name to say “x”
2 – in that folder “x”, compress all files and sub-folders with path (use “zip -rjm”??)
3 – rename the zip file to x.zip
4 – delete all the files that created the zip file.
So let’s say the folder structure is:
Vacation
- New York
- Pictures
- Text
In Finder I select New York
I want to create a zip file in the folder New York
This zip file is named New York and does a “zip -rjm”. So I want to recuse the subfolders and move the files to the zip file keeping the subfolder path. Then I can unzip the file and the subfolders would be restored.
This seems like something that would be a popular macro. Any help would be greatly appreciated!
Yes. The right-click, Compress doesn’t move files to a zip file, recuse the subfolders, or store the path…I am looking for something a little more than that.
Yes, “Recurse”. I don’t know what a flattened file list is. I want to be able to unzip the file and the subfolders and the files in those subfolders restored.
After further review the “Compress” is almost correct except I need it to “move” the files into the zip file, not “add”…
I need it to "move" the files into the zip file, not "add"....
i.e. compress the folder tree to a zip archive file and then delete the folder tree itself ?
( move = copy + delete )
The deletion stage is a bit tricky, because the only way of testing that the compression worked (and that you really do have a backup) is to decompress somewhere and verify.
Not sure that I would personally want to automate large-scale deletions ...
Don't the better tools use a checksum to verify file integrity?
If you moved to Trash rather than a true delete, then you would have a backup, for a while. And then there are always Time Machine backups.
I used PKZip and WinZip for years back in my Windows days (ugg) for the very purpose @Kurt_Kessler stated. I routinely "moved" files from their normal state to a zip file, and I don't recall every having an issue with loss of data/files.
But then we each have our own pain/risk tolerance.
If you go to terminal and type “zip” you will find a -m parameter.
-m move into zipfile (delete OS files)
This parameter instructs zip to basically delete the OS file after the zip. I remember this parameter from my pkzip days in DOS. We used it for years with no problems.
Zip 3.0 (July 5th 2008). Usage:
zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]
The default action is to add or replace zipfile entries from list, which
can include the special name - to compress standard input.
If zipfile and list are omitted, zip compresses stdin to stdout.
-f freshen: only changed files -u update: only changed or new files
-d delete entries in zipfile -m move into zipfile (delete OS files)
-r recurse into directories -j junk (don't record) directory names
-0 store only -l convert LF to CR LF (-ll CR LF to LF)
-1 compress faster -9 compress better
-q quiet operation -v verbose operation/print version info
-c add one-line comments -z add zipfile comment
-@ read names from stdin -o make zipfile as old as latest entry
-x exclude the following names -i include only the following names
-F fix zipfile (-FF try harder) -D do not add directory entries
-A adjust self-extracting exe -J junk zipfile prefix (unzipsfx)
-T test zipfile integrity -X eXclude eXtra file attributes
-y store symbolic links as the link instead of the referenced file
-e encrypt -n don't compress these suffixes
-h2 show more help
You could experiment with building and executing the zip command line that you want,
using an Execute JavaScript for Automation (or AppleScript or Bash) action in Keyboard Maestro.
The elements of a JS action might look a bit like this:
(function () {
'use strict';
// selectedPaths :: () -> [pathString]
var selectedPaths = function () {
return Application('Finder')
.selection()
.map(function (x) {
return decodeURI(x.url())
.slice(7);
});
};
var strCMD = 'zip -r ~/testArchive3 ' + selectedPaths()
.map(function (s) {
return '"' + s + '"';
}) // paths quoted
.join(' '); // spaces between quoted paths
var a = Application.currentApplication(),
sa = (a.includeStandardAdditions = true, a);
return strCMD + ' -->\n\n' + sa.doShellScript(strCMD);
})();
If you want to change the name of the zip file, just set a new variable in KM and then change the line to zip -rm "$KMVAR_<thevarname>" "$BASE" where <thevarname> is the name of your variable
It does it one at a time. Based on the request, he wanted to compress a single folder into an archive. The bash script doesn’t handle this, the for-loop does within KM
The syntax for compressing multiple files with zip is zip file.zip file1 file2 file3
Here’s a little more context into what’s happening with the script:
SAVE_DIR=`dirname "$KMVAR_Path"`
Gets the directory name for the Path. If the path is /Users/myname/Desktop/My Folder then the dirname is /Users/myname/Desktop
BASE=`basename "$KMVAR_Path"`
This gets the name of the folder without the dirname. From the example above, we’d get “My Folder”
BASE_NO_EXT=${BASE%.*}
This isn’t necessary unless you’ve selected a file with an extension. This will strip off the “.txt” from a file name like “file.txt”
pushd "$SAVE_DIR"
push the save path into the directory stack
zip -rm "$BASE_NO_EXT" "$BASE"
zip up the folder
popd
pop the last path added to the directory stack. In our case here, it’s “$SAVE_DIR”
For compressing all of the selected files into a single archive, that’d take a bit more work. If someone’s looking for this particular solution, I’ll write it up, otherwise I’ll save myself some work
If that be the case, then it would be easy enough using the KM For Each to build the file list, then pass the entire list to the Bash Script. See anything wrong with that?
Thanks. I would like this, but if what I stated above will work, I think I can modify the macro to do it.
But if it is not too much trouble for you, I'd love to learn from an expert.
BTW, for any other Bash novices like me out there reading this, here is the complete, very detailed, Apple manual on Zip:
Although this page states it is for macOS 10.9, the zip version from doing a man zip in Terminal is "ZIP(1L)", the same as in the online manual. I hope that means they are the same version?
# creates an array from the multiple paths variable
IFS=';' read -r -a array <<< "$KMVAR_MultiPaths"
BASE_PATH=`dirname "${array[0]}"`
PATHS_TO_ZIP=''
# Loop through the array, get the base and base name just like before, and concatenate to our PATHS_TO_ZIP variable
# Concatenating with a new line is important. You'll see why below
for element in "${array[@]}"
do
BASE=`basename "$element"`
BASE_NO_EXT=${BASE%.*}
PATHS_TO_ZIP="$BASE_NO_EXT\\n$PATHS_TO_ZIP"
done
pushd $BASE_PATH
# zip didn't like passing the paths as a variable because of spaces. Echoing the paths and piping it to zip solves this
# -@ archives all of the paths passed in through stdout
echo $PATHS_TO_ZIP | zip -r -@ archive.zip
popd