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?

1 Answer 1

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.

3
  • 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 Commented Sep 1, 2016 at 8:48
  • If you want to exclude subdir4 in the zip, then just do a cd $0 . I will edit the answer
    – amisax
    Commented Sep 1, 2016 at 8:55
  • I tried with and without /.. but nothing happens. As mentioned, I just get my prompt back after half a second. Commented Sep 1, 2016 at 8:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .