Some additional thoughts to be aware of by looking closer to each line (previously I just glanced over).
This point is not directly affecting your example, but I want to make you aware of something I fall into myself. Its one of those Bash quirks. Other shells might handle it differently, only speaking about Bash here. For a regular for loop over files, its important to note that if no file exists, the variable will be set to the search string. So example for x in *.png; do, if no .png file is found, then x will be set to *.png literally. So depending on what you do in the loop this could be catastrophic. But Bash has an option for this specifically: shopt -s nullglob . Using this option, if no file is found, then x will be set to an empty string. More about Bash options: https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
for x in *.abcdefg; do echo "$x"; done
shopt -s nullglob
for x in *.abcdefg; do echo "$x"; done
BTW one can also do a read line by line without cat, by reading the file directly: (for some reasons Beehaw won't let me type the lower than character, so replace that, here a screenshot too):

while IFS= read -r line; do echo "Line: ${line}" ; done \< filenames.txt