2

Let have a directory with lots of individual .txt files. My purpose is to find the individual files in the directory, zip them with the same name (excluding .txt) individually and remove the original file.

It is very easy to use gzip like below:

find .* -type f | xargs gzip 

but I need to zip the files instead.

NOTE: I do not have sudo privilege

Siva
  • 9,077
TPArrow
  • 123
  • Is the zip package installed on the system that you are using? Do you just want to operate on the files in the current directory or in the subdirectores (if they exist)? Are there files in that directory other than the ones ending in .txt?` – Nasir Riley Jul 05 '19 at 10:46
  • How about 'zip -m .txt' ? – gerhard d. Jul 05 '19 at 10:47
  • 1
    @msp9011 yes only the current directory – TPArrow Jul 05 '19 at 10:49
  • @NasirRiley yes it is installed. Only current directory. Yes there are a mixture of files in the directory – TPArrow Jul 05 '19 at 10:50

2 Answers2

3

Consider:

$ ls -1
a.txt
b.txt
c.txt
d.jpg

The following command will zip each .txt file and remove the original file:

find . -maxdepth 1 -type f -name '*.txt' -exec zip -Tm {}.zip {} \;

Result:

$ ls -1
a.txt.zip
b.txt.zip
c.txt.zip
d.jpg

Note: we used the -T option to test the integrity of the archive before removing the input file. This is recommended in the zip man page for the -m option:

-m, --move
Move the specified files into the zip archive; actually, this deletes the target directories/files after making the specified zip archive. If a directory becomes empty after removal of the files, the directory is also removed. No deletions are done until zip has created the archive without error. This is useful for conserving disk space, but is potentially dangerous so it is recommended to use it in combination with -T to test the archive before removing all input files.

Note that the .txt part is still present in the filename. This is how gzip behaves as well.

To remove the .txt part:

If you don't want the .txt part to remain in the filename, the following command will achieve this:

find . -maxdepth 1 -name '*.txt' -type f -exec bash -c \
  'zip -Tm "${1%.*}".zip "$1"' inline-bash {} \;

Result:

$ ls -1
a.zip
b.zip
c.zip
d.jpg

Note: The order of predicates to the find command invocation above avoids applying -type f (which potentially involves an expensive lstat() system call) on those files whose names don't match the pattern *.txt. (ref)

Note: We provided inline-bash as the first argument to our inline script. This has two benefits:

  1. $0 within our inline script will be set to inline-bash. (Recall that "$0 expands to the name of the shell or shell script" —bash manual.) For an inline script executed with -c, using inline-bash, or similar, is logical for this purpose and results in more meaningful error messages than if we chose _, another popular choice.
  2. Positional parameters to our script will start at 1 as usual.

Supplying a 0th argument to inline scripts, and what to call it, is discussed in an article on Using Find (mywiki.wooledge.org) and in an answer by Stéphane Chazelas to the question Is it possible to use find -exec sh -c safely?.

2

From man:

  -m
   --move
          Move  the  specified  files  into the zip archive; actually, this deletes the target directories/files after making the specified zip archive. If a directory
          becomes empty after removal of the files, the directory is also removed. No deletions are done until zip has created the archive without error.  This is use-
          ful  for  conserving  disk  space, but is potentially dangerous so it is recommended to use it in combination with -T to test the archive before removing all
          input files.

To compress ann files in current direstory

zip -m test.zip *.txt

Try this,

for i in *.txt; 
do
  zip -m "${i%.*}.zip" "${i%.*}".*; 
done

The above code will take all file with .txt as extension in a for loop and zip each file with their prefix name...

Siva
  • 9,077