Search code examples
bashfile-iowhile-loopstring-concatenation

Bash issue with concatenation within while read loop


With the following code, I'm attempting to construct an output array of start/end pairs to use elsewhere in the script from a pregenerated input file. However I'm running into an issue where instead of the end data being concatenated onto the start data, it seems to be overwriting what is already there?

#!/bin/bash

echo "Init arrays"
far=()
near=()
echo "Start while"
while read -u2 line; do
    echo "    $line"
    if [[ "$line" == "Far Start"* ]]; then
        far+=(${line##* })
        echo ${far[-1]}
    elif [[ "$line" == "Far End"* ]]; then
        far[-1]+="-${line##* }"
        echo ${far[-1]}
    elif [[ "$line" == "Near Start"* ]]; then
        near+=(${line##* })
        echo ${near[-1]}
    elif [[ "$line" == "Near End"* ]]; then
        near[-1]+="-${line##* }"
        echo ${near[-1]}
    fi
done 2<screenlog.0

echo
echo "  Far array"
for each in "${far[@]}"
do
  echo "$each"
done
echo "  Near array"
for each in "${near[@]}"
do
  echo "$each"
done

Input file (screenlog.0):

User Input: 955
Stepping Pass 1/6
Far Start 213994
Far End 216994
Near Start 221795
Near End 224795
Stepping Pass 2/6
Far Start 229596
Far End 232596
Near Start 237397
Near End 240397
Stepping Pass 3/6
Far Start 245198
Far End 248198
Near Start 252999
Near End 255999
Stepping Pass 4/6
Far Start 260800
Far End 263800
Near Start 268601
Near End 271601
Stepping Pass 5/6
Far Start 276402
Far End 279402
Near Start 284203
Near End 287203
Stepping Pass 6/6
Far Start 292004
Far End 295004
Near Start 299805
Near End 302805
Finished!

Erroneous output:

Init arrays
Start while
    User Input: 955
    Stepping Pass 1/6
    Far Start 213994
213994
    Far End 216994
-216994
    Near Start 221795
221795
    Near End 224795
-224795
    Stepping Pass 2/6
    Far Start 229596
229596
    Far End 232596
-232596
    Near Start 237397
237397
    Near End 240397
-240397
    Stepping Pass 3/6
    Far Start 245198
245198
    Far End 248198
-248198
    Near Start 252999
252999
    Near End 255999
-255999
    Stepping Pass 4/6
    Far Start 260800
260800
    Far End 263800
-263800
    Near Start 268601
268601
    Near End 271601
-271601
    Stepping Pass 5/6
    Far Start 276402
276402
    Far End 279402
-279402
    Near Start 284203
284203
    Near End 287203
-287203
    Stepping Pass 6/6
    Far Start 292004
292004
    Far End 295004
-295004
    Near Start 299805
299805
    Near End 302805
-302805
    Finished!

  Far array
-216994
-232596
-248198
-263800
-279402
-295004
  Near array
-224795
-240397
-255999
-271601
-287203
-302805

With regards to the expected results, the far array should end up looking like the following, (IE the start number followed by the delimiter followed by the end number). The near array should be the same, simply drawn from the near data instead.

[0] 213994-216994
[1] 229596-232596
[2] 245198-248198
[3] 260800-263800
[4] 276402-279402
[5] 292004-295004

I've attempted the array[-1]="${array[-1]}-${line##* }" syntax with the same results, as well as altering the delimiter and referencing the last element of the array with ${array[@]:-1}.

Edit: As suggested by William I tried replacing all instances of the far[-1] syntax with the far[$((${#far[@]}-1))], which resulted in the same erroneous output as the far[-1] syntax.


Solution

  • instead of for each .. echo .., use declare -p far near to see if there is no not printable chars

    may print something like

    declare -a far=([0]=$'213994\r-216994\r' [1]=$'229596\r-232596\r' [2]=$'245198\r-248198\r' [3]=$'260800\r-263800\r' [4]=$'276402\r-279402\r' [5]=$'292004\r-295004\r')
    declare -a near=([0]=$'221795\r-224795\r' [1]=$'237397\r-240397\r' [2]=$'252999\r-255999\r' [3]=$'268601\r-271601\r' [4]=$'284203\r-287203\r' [5]=$'299805\r-302805\r')
    

    if that's the case '\r' characters can be removed, addding

    line=${line%$'\r'}
    

    just after read (more exactly after do otherwise while loop would never end)