1

I have the following directory structure:

/Data
 - file 1
 - file 2

  /Folder1

   - file 3
   - file 4

  /Folder2
   - file 5
   - file 6

    /Folder3
      - file 7
      - file 8

In Linux I want to zip files (excluding folders) in every directory and create a 7z (or zip) archive in each folder resulting the following:

/Data
     Data.7z (Note: this should contain only file1 & 2, not any sub directories)

      /Folder1

       Folder1.7z (this should contain only file3 & 4, not any sub directories)

      /Folder2
       Folder2.7z (this should contain only file5 & 6, no Folder3)

        /Folder3
          Folder3.7z (should contain only file7 & 8)

Following script works in the first directory but not in the sub-directories :

for i in */ ; do base=$(basename “$i”) ; cd $base ; 7za a -t7z -r $base * ; .. ; cd .. ; done;

How can I achieve this?

  • are you looking specifically for Bash, or are you looking for any solution in general? – Thomas Ward Feb 12 '18 at 23:17
  • I'm looking for a solution. – alien250 Feb 12 '18 at 23:32
2

If you want to use 7z, the tricky part seems to be persuading it not to recurse; the documentation's indicated -r- switch appears to be non-functional, and the suggested workaround from the software's author is to exclude subdirectories with the wildcard expression -x!*/

So, given

$ tree Data
Data
├── file1
├── file2
├── Folder1
│   ├── file3
│   └── file4
├── Folder2
│   ├── file5
│   └── file6
└── Folder3
    ├── file7
    └── file8

3 directories, 8 files

then

find Data -type d -execdir sh -c 'cd "$1" && 7z a "$1".7z -x!*/ && cd -' sh {} \;

results in

$ tree Data
Data
├── Data.7z
├── file1
├── file2
├── Folder1
│   ├── file3
│   ├── file4
│   └── Folder1.7z
├── Folder2
│   ├── file5
│   ├── file6
│   └── Folder2.7z
└── Folder3
    ├── file7
    ├── file8
    └── Folder3.7z

3 directories, 12 files

where for example we can check that Folder2.7z contains only its own folder's files using

$ 7z l Data/Folder2/Folder2.7z 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_CA.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM)2 Duo CPU     P9600  @ 2.53GHz (1067A),ASM)

Scanning the drive for archives:
1 file, 128 bytes (1 KiB)

Listing archive: Data/Folder2/Folder2.7z

--
Path = Data/Folder2/Folder2.7z
Type = 7z
Physical Size = 128
Headers Size = 128
Solid = -
Blocks = 0

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2018-02-12 18:37:37 ....A            0            0  file5
2018-02-12 18:37:37 ....A            0            0  file6
------------------- ----- ------------ ------------  ------------------------
2018-02-12 18:37:37                  0            0  2 files

Note: !*/ may require additional escaping in environments (such as the interactive bash shell) where ! is a history expansion operator.

  • Brilliant! This is exactly the result I wanted. I can use rsync to copy all the 7z files to another directory. Thank you for your time! – alien250 Feb 13 '18 at 12:48
0

This is untested code, only used with 'echo', since I don't like to end with multiple zip files. And it is phantasy zip syntax, since I don't know 7za, but I will explain:

find . -type d -execdir /.../ad-hoc.sh {} ";"

The script ad-hoc.sh has to be adressed with an absolute path and should not be in the current path, to not affect the outcome, but it might be in the parentdir:

find . -type d -execdir $PWD/../ad-hoc.sh {} ";"

and, if not made executable, be explicitly invoked:

find . -type d -execdir bash $PWD/../ad-hoc.sh {} ";"

Find shall look in the current dir, only for files of type d (dirs), where to -execute a bashscript with parameter {}, the directory found.

Ok - what is the ad-hoc.sh, we execute in the dir and subdirs? It's another find:

#!/bin/bash
dir=$1
find $dir -maxdepth 1 -type f -exec echo zip -o "$dir.zip" {} +

-maxdepth 1 prevents find to search subdirs, -type says to just operate on files. -exec launches a command, for testing "echo zip ...", but if it looks promising (you do backups often, don't you?), you - well, here starts my pseudo code: -o:= -output "$PWD.zip", and {} + is the file list.

tree
.
├── buch-klein.kry
├── buch.kry
├── crypt
│   ├── moveto.sh.crypt
│   └── sub1
│       ├── foo.crypt
│       └── sub2
│           └── bar.crypt
├── original
│   ├── 1
│   │   └── 2
│   │       └── 3
│   ├── moveto.sh
│   └── sub1
│       └── sub2
│           └── up3 -> ../../../nr
├── outputfile.txt
├── rot.sh
└── zoom.sh

find . -type d -execdir $PWD/../ad-hoc.sh {} ";" 
zip -o ./..zip ././buch-klein.kry ././rot.sh ././buch.kry ././zoom.sh ././outputfile.txt
zip -o ./original.zip ./original/moveto.sh
zip -o ./crypt.zip ./crypt/moveto.sh.crypt
zip -o ./sub1.zip ./sub1/foo.crypt
zip -o ./sub2.zip ./sub2/bar.crypt

Every file with extension is a regular file, and every file without is a directory or a symlink to a dir (up3).

The {} has to be the last element of a find -exec command before the terminating ";" or +, so you have to build your 7z-command accordingly.

so if your 7za command is

      7za a -t7z -r $dir.7za *

the ad-hoc.sh might look like this:

#!/bin/bash
dir=$1
find $dir -maxdepth 1 -type f -exec echo 7za -t7z -r "$dir.7za" {} +
  • I tried this once and didn't work for me. I'll try again. Thanks for your time! – alien250 Feb 13 '18 at 12:50
  • Well, that error report isn't very useful. – user unknown Feb 13 '18 at 13:28

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.