1

I have the following code which works:

for file in $(find $1 -maxdepth 10000 -xdev -ignore_readdir_race); do
    if [[ "$file" =~ ^($OP0|$OP1|$OP2|$OP3|$OP4|$OP5|$OP6|$OP7|$OP8|$OP9)$ ]]; then (( SkipCnt++ )) # Count of skipped files
        elif [[ ! -e "$file" ]] ; then (( StalCnt++ ))                      # Count of files that existed last run, but don't now
        elif [[ ! -s "$file" ]] ; then (( ZeroCnt++ ))                      # Count of zero sized files
        elif [[ -d "$file" ]] ; then (( DirCnt++ ))                         # Count of directories
        elif [[ -h "$file" || -L "$file" ]] ; then (( LinkCnt++ ))          # Count of symbolic links
        elif [[ -c "$file" ]] ; then (( CdevCnt++ ))                        # Count of character devices
        elif [[ -b "$file" ]] ; then (( BdevCnt++ ))                        # Count of block devices
        elif [[ -p "$file" ]] ; then (( PipeCnt++ ))                        # Count of pipes
        elif [[ -S "$file" ]] ; then (( SockCnt++ ))                        # Count of sockets
        elif [[ -f "$file" && -s "$file" ]] ; then                          # File must exist, and not be any of the above.

You can use any one of these three, listed fastest to slowest

        tar -cS --no-recursion --warning=none "$file" &>/dev/null
        # cp --preserve=all --reflink=never "$file" /dev/null
        # cat "$file" 1>/dev/null

        (( FileCnt++ ))                                                 # Count of files cache-loaded
    else
        (( SkipCnt++ ))                                                 # Count of any files not otherwise processed.
fi

I'm attempting to convert it to a case statement, but I can't figure it out... what I've got so far (I just copied each if statement to the case statement, but it keeps throwing an error):

The error:

/usr/local/bin/cachewarmup: line 43: syntax error near unexpected token `"$file"'
/usr/local/bin/cachewarmup: line 43: `          [[ "$file" =~ ^($OP0|$OP1|$OP2|$OP3|$OP4|$OP5|$OP6|$OP7|$OP8|$OP9)$ ]]) (( SkipCnt++ ));;'

The (non-working) code:

for file in $(find $1 -maxdepth 10000 -xdev -ignore_readdir_race); do
    case true in
            [[ "$file" =~ ^($OP0|$OP1|$OP2|$OP3|$OP4|$OP5|$OP6|$OP7|$OP8|$OP9)$ ]]) (( SkipCnt++ ));;
            [[ ! -e "$file" ]]) (( StalCnt++ ));;
            [[ ! -s "$file" ]]) (( ZeroCnt++ ));;
            [[ -d "$file" ]]) (( DirCnt++ ));;
            [[ -h "$file" || -L "$file" ]]) (( LinkCnt++ ));;
            [[ -c "$file" ]]) (( CdevCnt++ ));;
            [[ -b "$file" ]]) (( BdevCnt++));;
            [[ -p "$file" ]]) (( PipeCnt++));;
            [[ -S "$file" ]]) (( SockCnt++ ));;
            [[ -f "$file" && -s "$file" ]]) tar -cS --no-recursion --warning=none "$file" &>/dev/null; (( FileCnt++ ));;
            *) (( SkipCnt++ ));;
    esac

Any ideas on what I'm doing wrong?

1 Answers1

1

Your case of if and case

case something in interprets something as a string, not as a command. It makes little sense (if any at all) for something to be a fixed string like true.

Usually a variable is used there. It provides a non-fixed string that gets compared to pattern(s) present later in code.

In the logic of your original code there is no such variable. Your tests are commands (well, [[ is a shell keyword, not strictly a command; but it's still something that returns exit status like a command, totally not a string). If all the commands tried to compare the value of a certain variable to some patterns then probably they could be converted to case … esac. Among your commands the one with =~ does this, but the rest do something else. This does not really qualify to be converted to case … esac.

In general even tests with =~ may or may not qualify to be converted to case … esac. The problem is =~ uses a regex, while patterns for case are not regular expressions; in general it may be impossible to convert one scheme to the other strictly.

Stick to if … elif … fi, do not try to convert to syntax that does not fit.


Broader view on if and case

if depends on the exit status of some shell code that returns exit status. It may be a command (like grep or [) or something else (like [[ or a pipeline) that returns exit status like a command would. Basically after if (or elif) you can put arbitrary shell code as a condition.

case directly compares strings. It does not rely on the exit status of anything. While in principle you can convert string comparison (case) to shell code that implements the same string comparison (for if), converting arbitrary shell code (if) to string comparison (case) is cumbersome (if possible at all).


Side notes