0

I am trying to compress all folder in dir based on some regex so I used grep to filter out the output now i need to use tar and folder name.

For example I want to .tar.gz each top level directory to its own archive. Dir name must start with "web_" and not end with ".tar.gz".

How can I catch grep output to a varibel so it looks like this:

find . -maxdepth 1 -mindepth 1 -type d -print | grep -v \.tar\.gz$ | grep ^\./web_ | exec tar -czf $name.tar.gz $name

or with ls -h

ls -h | grep -v \.tar\.gz$ | grep ^web_ | exec tar -czf $name.tar.gz $name

Selection "find ...":

root@4a94aef49e3a:/home# find . -maxdepth 1 -mindepth 1 -type d -print | grep -v \.tar\.gz$ | grep ^web_
./web_demozip1
./web_demozip2

Selection "ls -h":

root@4a94aef49e3a:/home# ls -h | grep -v \.tar\.gz$ | grep ^web_
web_demozip1
web_demozip2

Example:

# fixed name works but its overwrite itself so I need to catch a var from grep
ls -h | grep -v \.tar\.gz | grep ^_web | exec tar -czf web_demozip1.tar.gz web_demozip1

root@4a94aef49e3a:/home# pwd
/home
root@4a94aef49e3a:/home# tree .
.
├── web_demozip1
│   └── somefile.txt
├── web_demozip1.tar.gz
└── web_demozip2
    └── somefile.txt
4
  • 1
    Please edit your question and explain, in words, exactly what directories should be compressed and what directories should not. None of your approaches are safe for directories with strange names (spaces, newlines, globbing characters etc) but we can't give you a safe command unless you explain what you want to match.
    – terdon
    Aug 23 at 12:06
  • Not file, but for each find (=directory on first level) is what I read from the question.
    – pLumo
    Aug 23 at 12:17
  • @pLumo, ah good point, thanks
    – ilkkachu
    Aug 23 at 12:19
  • Yes I am trying to create separate archive for each folder. Thanks
    – DevWL
    Aug 23 at 12:20
5

You don't need to filter find results using grep. Use the filter capabilities of find instead.

find . -maxdepth 1 -mindepth 1 -type d \
  -name 'web_*' \
  -exec tar czf {}.tar.gz {} \;

find can also filter using regex, but it is not needed for your example. See here how to do.

3
  • I noticed that it also matches directories containing space char within its name (which is great) and @ilkkachu answer does exacly same so both are valid solutions. Thanks guys.
    – DevWL
    Aug 23 at 14:10
  • Note that not all find implementations will substitute the {} if if not on its own argument as a whole. But then again, not all support -mindepth / -maxdepth which are non-standard extensions. Even fewer support -regex, and those that do support different regexp syntax. Aug 23 at 14:19
  • -mindepth and -maxdepth are supported by most, but not all find implementations. Expanding {} if this is not the pure single argument text is supported by few find impementations and -regex seems to be gfind specific. The biggest problem with gfind is that it's documentation encourages people to use non-standard methods like e.g. -not, even in case that an identical standard method exists since more than 45 years. This seems to be based on the wish to create a vendor lock in. See libfind documention as better example schilytools.sourceforge.net/man/man1/sfind.1.html
    – schily
    Aug 23 at 19:21
4

If you just want to archive each directory in the current directory, one tarball per directory, I would go with a shell loop:

for dir in ./web_*/; do
    tarname=${dir%/}.tar.gz
    tar -czf "$tarname" "$dir"
done

The trailing slash on the glob (./web_*/) makes it match only directories, and the ${dir%/} returns the string with that suffix removed and a directory called like that is probably an error anyway.

Note that I dropped the condition checking the names against the .tar.gz suffix, since we're already looking only at directories and those are probably files. If you really do have directories named like that, you could add [[ $dir == *.tar.gz/ ]] && continue as the first line in the loop. (In Bash/ksh/zsh.)

If you want more complex patterns, look into Ksh-style extended globs in Bash (shopt -s extglob), or zsh's own extended globs in zsh.

3
  • 2
    Note that ./web_*/ also includes symlinks to directories, and tar -c on those will just archive the symlink, not the contents of the directory it points to. Use web_*(/) in zsh to only include plain directories. Aug 23 at 12:41
  • @StéphaneChazelas thanks for that will keep that in mind. ilkkachu Thanks for this solution works like a charm!
    – DevWL
    Aug 23 at 14:12
  • 1
    Sorry, tar -czf file.tar.gz link/ will archive the contents of the directory, it's tar -czf file.tar.gz link that would only archive the symlink. Aug 23 at 14:21
0

Using xargs

I also found out that i can use XARGS not sure if this is a good aproach so let me know in the comment what you think of this. I am pretty sure that i should go with @ilkkachu or @pLumo solutions but just to prove it can be done:

cdate=$(date '+%Y-%m-%d-%H-%M')
ls -h | grep -v \.tar\.gz$ | grep ^web_ | xargs -I {} tar -czf {}_$cdate.tar.gz {}

Which would output:

root@4a94aef49e3a:/home# tree .
.
├── web_demozip1
│   └── somefile.txt
├── web_demozip1_2021-08-23-14-43.tar.gz
├── web_demozip2
│   └── somefile.txt
├── web_demozip2_2021-08-23-14-43.tar.gz
├── web_ spacedir3
│   └── somefile.txt
└── web_ spacedir3_2021-08-23-14-43.tar.gz

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.