2024-12-10

Bash while read line without subshell and arrays with IFS

Just a few notes about script where writing it took me far more time than it shoud :)

First, while read line without subshell. So I was attempting to do something like this:

count=0
export IFS=$'/n'
cat file.log | while read line; do
  let count+=1
done
echo $count

But because of the pipe, while runs in a subshell, so whatever I do to the count variable there is lost once I exit the loop, so echo prints 0 at the end. Using answer here I used this:

count=0
trap 'rm -rf $TMPFIFODIR' EXIT
TMPFIFODIR=$( mktemp -d )
mkfifo $TMPFIFODIR/mypipe
cat file.log > $TMPFIFODIR/mypipe &
export IFS=$'/n'
while read line; do
  let count+=1
done < $TMPFIFODIR/mypipe
echo $count

Now the second problem. Inside the loop I was using this to get first number from the line (because I think it is bit cheaper to do it this way than using sed or something):

numbers=( ${line//[!0-9]/ } )
count="${numbers[0]}"

This code did not worked for me and I was getting string with numbers and spaces in count - something that converting to array (these brackets) should take care about. It took me quite a bit of time to realize that when I'm exporting IFS to only newline, I'm breaking this. So I ended with just setting IFS for that read like this:

while IFS=$'\n' read line; do
  ...
done < $TMPFIFODIR/mypipe