Home > Mobile >  Bash If Statement Incorrectly Specified
Bash If Statement Incorrectly Specified

Time:10-29

I'm not specifying my If Statement in bash correctly, but I'm not sure what exactly I'm doing wrong.

I have hundreds of participants who completed differing numbers of study procedures so they have a different number of available files. I added an if statement to specify how many files we should expect to find for each participant after a processing procedure. It should iterate through each participant, assign a value between 3 and 5 to a variable based on the ID, then use the value of that variable to look for a certain number of files.

# SUBJECTS is a concatenated list of IDs 
for i in ${SUBJECTS}; do

    # Different subjects have a different number of files. 
    # I want to specify how many files bash should look for based on ID.
    # This first if statement should identify whether the current iteration of i matches any of the identified IDs. 
    # If so, it should specify that bash should be looking for 4 files.
    if [[ ${i} -eq "XX001" ||\
          ${i} -eq "XX002" ||\
          ${i} -eq "XX003" ]]; 
    then 
        NFILES=4

    # ... and if any iterations of i match these IDs, bash should look for 3 files
    elif [[ ${i} -eq "XX004" ||\
            ${i} -eq "XX005" ]]; 
    then 
        NFILES=3

    # ... and for everyone else, bash should look for 5 files.
    else
        NFILES=5
    fi

    # Now, for each participant, iterate through the number of files we expect they should have
    for j in `seq -w 1 ${NFILES}` ; do

        # ... and check whether a file of this name exists in this location
        if [ ! -f "${FILEPATH}/FILENAME_${i}_${j}.nii.gz" ]; then

            # If it does not, note which ID and File is missing at the end of this document
            echo "${i}; FILE ${j}" >> ${FILEPATH}/MissingFiles.txt

        fi

    done

done

If I run this script without the first If Statement, it correctly identifies that files exist for participants, but it just also gives a lot of false negatives too (e.g., if a participant only has three files, the output will suggest files 4 and 5 are missing, even though it's what is expected). When I add the If Statement, the computer seems to assume all participants meet the first condition for some reason, so it thinks all participants have 4 files.

I'd been using a lot of other threads like this one and this one to find solutions, but without much luck. Any help is greatly appreciated!

CodePudding user response:

In a [[ ]] conditional expression, the -eq operator does numeric comparisons, not string comparisons; you want the = operator (or equivalently ==).

Note: the syntax and operator semantics are confusingly different between [[ ]], [ ], and (( )) expressions. See this Unix&Linux answer and BashFAQ #31. If you're writing for bash (i.e. your script doesn't need to be able to run under dash, or some other shell that doesn't have [[ ]]), I recommend avoiding [ ] entirely and using [[ ]] for most tests, but (( )) is ok for strictly arithmetic things.

In this case, though, since you're comparing a variable against a bunch of possible values, I'd recommend a case statement. That's what they're for.

case "$i" in
    XX001 | XX002 | XX003 )
        NFILES=4 ;;
    XX004 | XX005 )
        NFILES=3 ;;
    ...
    * )
        NFILES=5 ;;
esac

You can also use glob patterns here, so XX00[123] ) would match "XX001", "XX002", or "XX003".

I'd also recommend switching to lower- or mixed-case variable names, to avoid conflicts with the many all-caps names that have special meanings.

  • Related