serhii.net

In the middle of the desert you can say anything you want

20 Jan 2022

zsh and bash iterate for each line in command or in file

I seem to keep googling this. … and this is not final and magic and I should actually understand this on a deeper level.

Not today.

So.

TL;DR for copypaste

Reading lines in a file:

while IFS="" read -r p || [ -n "$p" ]
do
  printf '%s\n' "$p"
done < peptides.txt

For outputs of a command:

while read -r p; do
	echo $p;
done < <(echo "one\ntwo")

Easy option with cat

Otherwise: Easy option that I can memorize, both for lines in command and in file that will will skip the last line if it doesn’t have a trailing newline:

for word in $(cat peptides.txt); do echo $word; done

Same idea but with avoiding this bug:

cat peptides.txt | while read line || [[ -n $line ]];
do
   # do something with $line here
done

Correct option without cat

  1. Same as first cat option above, same drawbacks, but no use of cat:

    while read p; do
      echo "$p"
    done <peptides.txt
    
  2. Same as above but without the drawbacks:

    while IFS="" read -r p || [ -n "$p" ]
    do
      printf '%s\n' "$p"
    done < peptides.txt
    
  3. This would make command read from stdin, 10 is arbitrary:

    while read -u 10 p; do
      ...
    done 10<peptides.txt
    

(All this from the same SO answer1).


In general, if you’re using “cat” with only one argument, you’re doing something wrong (or suboptimal).

Nel mezzo del deserto posso dire tutto quello che voglio.