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

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
  • Works perfectly. I put the: if [ -d "$file" ]; then ... before the 7z line. Does just what I want. – andyNilson Mar 4 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. – Kusalananda Mar 4 at 16:06
  • @ Kusalananda. Do i add it to filetype, to the for statement or in between? – andyNilson Mar 4 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. – Kusalananda Mar 4 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. – andyNilson Mar 4 at 17:48

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.