0

I have a folder structure that looks like this:

0/1/2 and the numbers goes from {0..9}

I tried writing a bash shell script so that I can compress each of the folders like this:

#!/bin/bash
for i in {0..9};
  do
  cd $i
    for j in {0..9};
      do
      cd $j
        for k in {0..9};
         do
           tar -czvf $i$j$k.tar.gz $k;
         done
      done
 done

It seems to be able to create the names for the .tar.gz files ok, but it won't traverse through the directory structure to be able to create them for each of the folders inside the folders.

I'm not 100% sure what I am doing wrong with this script.

What I want it to do is to go to 0/0/ and then create the .tar.gz file for folders {0..9}.

And then go to 0/1/ and do it again.

And then go to 0/2/ and do it again, etc.

Until all of the folders have been cycled through, and the .tar.gz files have been created.

It seems to just saying in 0/0/ and just keep compressing the same files over and over again, and it won't move on to the next folder.

Any help is greatly appreciated.

(Disclaimer: I'm not a programmer nor a developer, so this is new territory for me.)

(Background: this is for me to back up my Photoprism data storage (as it has about 2.5 million pictures and takes up about 1.6 TB of space or so). I tried sending it straight to LTO-8 tape and I guess that because there are so many small files, LTFS ran into an out of memory exception error such that when I eject the tape and try to load it back in, it automatically spits the tape back out because of said out-of-memory error; but that's a whole 'nother question. So I figure that if I compress the files, then it will have fewer files that LTFS is dealing with, and therefore; that should help fix the LTFS/LTO-8 tape drive error.)

Thank you.

3
  • 2
    You are entering directories with cd, but I don't see you ever coming back out of them...
    – Kusalananda
    Commented Jul 5 at 11:13
  • "0/1/2 and the numbers goes from {0..9}" - which of these numbers are {0..9}? Just the first zero or the others too? Commented Jul 5 at 11:28
  • "You are entering directories with cd, but I don't see you ever coming back out of them..." Ahhh...okay. Thank you. Whoopsies. ""0/1/2 and the numbers goes from {0..9}" - which of these numbers are {0..9}? Just the first zero or the others too? – Chris Davies" The others as well. Commented Jul 5 at 19:14

2 Answers 2

0

Instead of cd, use the -C option of tar:

Something like (untested):

#!/bin/bash
for i in {0..9}
  do
    for j in {0..9}
      do
        for k in {0..9}
         do
           [ -d $i/$j/$k ] && tar -C $i/$j -czvf $i$j$k.tar.gz $k
         done
      done
 done

I added a [ -d ... ] test in case some of these directories don't exist.

Note: Conveniently, the .tar.gz files are created in the current directory, not in the directory where tar switches to using -C! So you have them all in one place.

Solution in TXR Lisp:

(each ((digits "000".."999"))
  (match `@{i 1}@{j 1}@k` digits
    (if (path-dir-p `@i/@j/@k`)
      (sh `tar -C @i/@j -czvf @i@[email protected] @k`))))

Let string generation generate the digits. Destructure them into variables with match; then the same core logic: does the i-j-k directory exist; if so, tell tar to switch to i/j, make the ijk archive out of k.

Alternative without the match stuff; with each-prod we can condense nested loops:

(each-prod ((i "0".."9") (j "0".."9") (k "0".."9"))
  (if (path-dir-p `@i/@j/@k`)
    (sh `tar -C @i/@j -czv0f @i@[email protected] @k`)))
3
  • I will admit that this solution probably works, but my idiot brain struggles to understand it. I appreciate the feedback, so I will try try it out/test it. Will this work if the three levels of directories also go from 00a to fff? (i.e. each level is actually really [0123456789abcdef], but my dummy brain, using the zsh-style brace notation for the expansion; I was running the script twice, the first time for the numbers and then the second time for the letters {a..f}. (Sidebar: this is why I shouldn't write code) Commented Jul 5 at 19:17
  • The bash shell script appears to be working. Thank you. I appreciate your help and also your explanation as well so that I can learn from the solutions. Commented Jul 5 at 21:02
  • @alpha754293 By the way, if for some reason you wanted the tar files to be above their respective "k" directories, then it would be simply tar -C ... -czvf $i/$j/$i$j$k.tar.gz. I.e. just prefix the relative path onto the tarball name.
    – Kaz
    Commented Jul 6 at 2:18
0

Your script, starting from /start, does

  • cd 0, after which you land in /start/0, then
  • cd 0, after which you land in /start/0/0, then
  • cd 1, after which you land in /start/0/0/1, not /start/0/1, then
  • cd 2, which likely fails as there's no /start/0/0/1/2.

If I had to use bash, I'd do:

#! /bin/bash -
shopt -s nullglob
for i in [0123456789]/[0123456789]/; do
  (
    CDPATH= cd "$i" && 
      for j in [0123456789]/; do
        j=${j%/}
        tar zcf "${i//\/}$j.tar.gz" "$j"
      done
  )
done

Note:

  • the (...) which starts a subshell, so cd only changes the current directory of that subshell
  • the && so we don't carry on if the cd failed
  • the CDPATH= in case there's a CDPATH in the environment which could make you land somewhere completely different.
  • the usage of globbing ([0123456789]) instead of zsh-style {0..9} brace expansion, so it only expands to directories that actually exists.
  • the trailing / (which we strip afterwards with ${j%/}, or ${i//\/} along with the other /s) to restrict the globbing to directories.
3
  • I appreciate you taking the time to expand the explanation of your solution. Thank you! It really helps me learn it. If my folder structure is really from [0123456789abcdef], can I replace [0123456789] with this instead or do I have to run the script twice -- the first time for the numbers and then the second time for the letters? (I am asking my stupid question because what's what my dummy brain was thinking about this problem earlier this morning.) Commented Jul 5 at 19:19
  • so I just tried this and if say, I start from /start, then I end up with files like: /start/3/0/3/03.tar.gz rather than /start/3/0/303.tar.gz My apologies for not stating more clearly what I was looking for or hoping to achieve. Sorry about that. Commented Jul 5 at 20:52
  • @alpha754293, ah yes, sorry, my bad. See if the edit works better. Commented Jul 5 at 21:54

You must log in to answer this question.

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