0

Want to 7zip all files in root/current folder except for all zip-files AND all 7z/7zip files. I can only get one of these to work at a time in one if ! statement:

for file in ./test2/* do if ! { `file $file | grep -i zip > /dev/null 2>&1` && `file $file | grep -i 7z > /dev/null 2>&1`; }; then ## Most of the zip utilities contain "zip" when checked for file type. ## grep for the expression that matches your case 7z a -mx0 -mmt2 -tzip "${file%/}.cbz" "$file" rm -rf "$file" fi done 

I have followed the "list" {list;}; standards from other posts, but no luck.


My current solution is to nest if statements, like so:

for file in ./test2/* do if ! `file $file | grep -i 7z > /dev/null 2>&1`; then if ! `file $file | grep -i zip > /dev/null 2>&1`; then ## first if its not 7z, now also if not zip. 7z a -mx0 -mmt2 -tzip "${file%/}.cbz" "$file" rm -rf "$file" fi fi done 

Only thing left is exclude directories. All files go. How to?

1 Answer 1

1

Get the output of file separately and then use that in multiple tests, or in a case statement:

for file in ./test2/*; do filetype=$( file "$file" ) if [[ $filetype == *7z* ]] || [[ $filetype == *zip* ]] then # skip these continue fi # rest of body of loop here done 

Or,

for file in ./test2/*; do filetype=$( file "$file" ) case $filetype in *7z*) continue ;; # skip these *zip*) continue ;; # and these esac # rest of body of loop here done 

You may also want to get file to output the MIME type instead of a free form text string. That could be done with file -i and would make the script slightly more portable (if you care about that). See the file(1) manual (man 1 file).

To exclude directories, just use

if [ -d "$file" ]; then continue fi 

before the call to file.

Alternatively, use short-circuit syntax:

[ -d "$file" ] && continue 

The continue statement, in all instances where it's used above, will skip the remainder of the current iteration and continue with the next iteration of the loop. I'm using when I have determined that the current value of $file is something that we don't want to process in this iteration. This is the opposite of what you do, which is to try to craft a set of tests for when the operations should be performed.

A /bin/sh-compatible script would look like this in the end:

#!/bin/sh for file in ./test2/*; do [ -d "$file" ] && continue filetype=$( file "$file" ) case $filetype in *7z*) continue ;; # skip these *zip*) continue ;; # and these esac # rest of body of loop here done 
6
  • Works perfectly. I put the: if [ -d "$file" ]; then ... before the 7z line. Does just what I want. Commented Mar 4, 2019 at 16:03
  • @andyNilson No. As I mentioned, it should go before the call to file, i.e. before assigning anything to filetype. Doing it later means you're calling file unnecessary. Commented Mar 4, 2019 at 16:06
  • @ Kusalananda. Do i add it to filetype, to the for statement or in between? Commented Mar 4, 2019 at 16:20
  • @andyNilson Between. The test of whether $file is a directory should be the first thing that happens in the loop. If it is a directory, the rest of that iteration should be skipped with continue. Commented Mar 4, 2019 at 16:53
  • Thanks for the clarifications. Added it before the filetype. Now working smoothly. Your last example for bin/sh works perfectly. My own 7z though, had to be fitted with -aou to keep it from overwriting files. As some files created already had 7z versions. Posting it above as a final solution. Commented Mar 4, 2019 at 17:48

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.