Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I need to gzip all files in a dir separately including all files in sub-directories without deleting the originals afterwards. So let's say I have index.html, I want to have at the end index.html.gzip AND index.html.

I am able to gzip all files in my dir via

gzip -r .

But I want to keep the original files also.

Is this possible?

share|improve this question

migrated from stackoverflow.com Oct 3 '12 at 7:36

This question came from our site for professional and enthusiast programmers.

add comment

4 Answers

up vote 8 down vote accepted
find . -type f | \
while read -r x
do
  gzip -c "$x" > "$x.gz"
done

The -c pushes the result to stdout and keeps the original alone. The disadvantage is, that you need to find the files yourself. For more sophisticated traversing, you can use find(1), however, like above: . searches starting from the current directory, and -type f returns the name of every regular file.

share|improve this answer
    
Why *.* in ls? –  user332325 Feb 15 '11 at 9:50
    
@pooh: *.* matches all regularly named files, and usually no directories. Of course, it only works in most cases and usually not if you need it. Then use the find command. –  Boldewyn Feb 15 '11 at 11:15
    
@Boldewyn: the question was to gzip all files in a dir. ls *.* won't pick files like TODO. –  user332325 Feb 15 '11 at 11:39
    
ls isn't needed at all: for x in *. However, using find should be find . -type f | while read -r x. –  Dennis Williamson Feb 15 '11 at 11:51
    
Updated answer. Thanks for the -r switch on read. –  Boldewyn Feb 15 '11 at 13:17
show 1 more comment
find . -type f -not \( -name '*.gz' -or -name '*[~#]' \) -exec sh -c 'gzip -c "{}" > "{}.gz"' \;

You could easily switch it around to include what you want to compress ( -name '*.txt -or -name '*.html etc.) instead of like now, excluding some files (already compressed, backup and temporary files).

Handles spaces in the filename just fine too.

Change gzip to echo gzip for testing. Or skip the -exec part all together.

Edit: Oh, I forgot to mention that this doesn't check if <target>.gz already exists. This may or may not be a problem.

Edit2: Ok, here we go with something that checks for existing file. If that may be wanted. Pardon the oneliney-ness.

while read file; do if [ ! -f "$file.gz" ]; then echo "Compressing $file"; gzip -c "$file" > "$file.gz"; else echo "Not overwriting $file.gz";  fi  done < <(find . -type f -not \( -name '*.gz' -or -name '*[~#]' \))

My find-foo is maybe not what it could be, it may very well be possible to skip directly in find.

share|improve this answer
1  
just read that -name should come before -type to avoid calling stat on every file. –  Ben Jul 17 '12 at 5:51
    
@Ben Makes sense, good input! For large trees it might be noticeable. –  plundra Jul 18 '12 at 8:06
add comment

Just add the -c option, I think this should work

share|improve this answer
    
This probably only works when gzipping a single file at a time. –  its_me Mar 30 '13 at 5:48
add comment
gzip -rc `ls` > archive.gz

Tested on Debian (gzip 1.3.12-6)

share|improve this answer
    
That creates one archive. The OP wants separate archives. ls is unnecessary, use *. –  Dennis Williamson Feb 15 '11 at 11:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.