Solebay Sharp
Solebay Sharp

Reputation: 533

Reading lines from each file in an array -- condition never succeeds

I'm trying to integrate a cat command into a for loop with the cat reading the element '$currentccoutput' but it seems (I think) that cat is reading the line literally rather than understanding that it's an array element with the name of a txt file.

#create an array of text files

currentccoutputs=($currentccfolder'/'*.txt*)

#basic for loop until I can get my cat command working

for currentccoutput in "${currentccoutputs[@]}"; do

    cat "$currentccoutput" | while read LINE; do

        # I have .txt files with three numbers per line
        # that I would like to read / use

        IFS=' ' read C1 C2 threshold
            if [ $C1 != $C2 ] && [ $threshold \> 0.2 ]; then
            echo "Huzzah!!!! Progress at last"
        fi

     done < "$currrentccoutput" # I don't know what 
                                # this backwards chevron
                                # does but other people
                                # have used it...
done

I've no doubt there are other imperfections with this snippet but I'm entirely new to creating scripts so I'm trying to keep things within the realms of what I know for now and hopefully sophisticated solutions will come later. (for now, I'm trying to get from island A to island B, where a few bits of wood and some hemp rope will be both understood and replicable. Whilst I appreciate advice on - and hope one day to build - a decent frigate, right now it might leave me somewhat confused).

I've never even used 'while' 'read' or 'LINE', I've pinched it from someone else's solution.

I have used the echo command to ensure it's not my paths that are wrong, just that I'm not using cat correctly.

Upvotes: 0

Views: 67

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295443

The only problem with how you're using cat is that you're overriding it with a (much better) shell-builtin redirection. That fine -- in fact, it's preferable; you shouldn't use cat unless you absolutely must.[1]

What is a problem is that you're running read LINE and then read C1 C2 threshold after each other, both coming from the same source.

This means that you read the first line of each file into the variable LINE (which your code never looks at again), and the second line into the variables C1, C2 and threshold. If there are more lines, you read the third into LINE, the fourth into C1/C2/threshold, etc.

If you don't want to skip every other line (starting at the first one), just take out the read LINE entirely, making your code something like:

#!/usr/bin/env bash
case $BASH_VERSION in '') echo "ERROR: This script must be run with bash" >&2; exit 1;; esac

currentccoutputs=( "$currentccfolder"/*.txt )

for currentccoutput in "${currentccoutputs[@]}"; do
    while IFS=$' \t\r' read -r c1 c2 threshold; do
        if [ "$c1" != "$c2" ] && [ "$(bc -l <<<"$threshold > 0.2")" = 1 ]; then
            echo "Huzzah!!!! Progress at last: c1=$c1; c2=$c2; threshold=$threshold"
        fi
     done < "$currentccoutput"
done

See:

  • BashFAQ #1 - How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
  • BashFAQ #22 - How can I calculate with floating point numbers instead of just integers? (describing the bc idiom used above)
  • BashFAQ #24 - I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read? (describing why cat | while read is a Bad Idea)

[1] - Yes, this means you should ignore many if not most of the examples of bash code you find online. Sturgeon's Law applies.

Upvotes: 3

Related Questions