2

in such a filesystem structure:

root/
    |
    container1/
    |         |
    |         subdir2/
    |                |
    |                subdir3/
    |                       |
    |                       subdir4/
    |                              |
    |                              file1
    |                              file2
    |                              subdir5/
    container2/
              |...

I need to zip everything:

  • under `/subdir4/``
  • without the /subdir4/ itself
  • in all potential /container/ subdirs of the root/directory
  • name the zip the same as the parent folder of the contents being zipped (in this case, it would be "subdir4.zip")

Please bear in mind:

  • these are not the real names of dirs and subdirs, it's just an approximation
  • I am using ZSH on a Mac OSX
  • I am quite new to Unix/Linux scripting

I would really like a shell-agnostic, simple, loop kind of solution so I can learn as much as possible and be flexible in modifying this solution for other potential cases.

Here is what I have tried so far, as suggested by friends:

find . -mindepth 5 -maxdepth 5 -type d -exec sh -c '
pushd "$0/..";zip -rFS "$(basename "$0").zip" "$(basename "$0")";popd ' {} \;

In the meantime, I have learned that this solution has the following drawbacks:

  • $0 should not be used as positional parameter because it is used in error reporting and/or as the shell script name (in my case, it's just a string)
  • basename and dirname are best avoided if using bash (read more here)
  • this syntax, with ... {} \;invokes as many shells as there are results, supposedly not efficient way of doing this type of operation

I should have been using:

  • $1 in my positional parameters
  • ... ;popd ' sh {} +

That one is supposed to get all the results in a sort-of an "array/list" and apply the commands within the string passed to the sh all at once.

Thanks!

BONUS POINTS: :)

  • can I name the resulting .zip same as /subdir3/ instead of as /subdir4/ from this hierarchy?
0

You can use awk to create the system command to execute

find * -mindepth 5 -maxdepth 5 -type d  | awk -F"/" '{system( "cd "$0"; zip -rF "$NF".zip *")}'

The -F splits the line on / , $0 represents the complete line and $NF has your actual directory name. There is no popd required since the system command executes in its own shell, and the parent shell stays in the current working directory.

  • Thank you for your answer, appreciate it! However, won't this solution include subdir4/ as well? I see that you first cd into the --parent-- of the subdir whose contents I wish to zip (..."cd "$0"/..")? I tried to run this but nothing happened, just got my prompt back – Alex Starbuck Sep 1 '16 at 8:48
  • If you want to exclude subdir4 in the zip, then just do a cd $0 . I will edit the answer – amisax Sep 1 '16 at 8:55
  • I tried with and without /.. but nothing happens. As mentioned, I just get my prompt back after half a second. – Alex Starbuck Sep 1 '16 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.