If you can avoid it, don't especially if it's to process text.
Most text utilities are already designed to process text one line at a time, and, at least for the GNU implementations, do it efficiently, correctly and handle error conditions nicely. Piping one to another which runs them in parallel also means you can leverage more than one processor to do the job.
Here:
<input.txt sed 's/^/tester /' > output.txt
Or:
<input.txt awk '{print "tester", $0}' > output.txt
More on that at: Why is using a shell loop to process text considered bad practice?
If it's not about text processing and you do need to run some command per line of a file, also note GNU xargs
where you can do:
xargs -rd'\n' -I@ -a input.txt cp -- @ @.back
for instance.
With the bash shell, you can get each line of a file into an array with the readarray
builtin:
readarray -t lines < input.txt &&
for line in "${lines[@]}"; do
do-some-non-text-processing-you-cannot-easily-do-with-xargs "$line" || break
done
POSIXly, you can use IFS= read -r line
to read one line off some input, but beware that if you redirect the whole while read
loop with the input file on stdin, then commands inside the loop will also have their stdin redirected to the file, so best is to use a different fd which you close inside the loop:
while
IFS= read -r line <&3 ||
[ -n "$line" ] # to cover for an unterminated last line.
do
{
do-some-non-text-processing-you-cannot-easily-do-with-xargs "$line" ||
break # abort upon failure if relevant
} 3<&-
done 3< input.txt > output.txt
read -r line
removes leading and trailing whitespace characters from the line that it reads provided they are in the $IFS
variable, though only the yash
shell honours that POSIX requirement. With most shells, that's limited to space and tab. ksh93 and recent versions of bash
do it for all single-byte characters considered as whitespace in the locale.
So to read a line and also strip leading and trailing blanks, you can do: IFS=$' \t' read -r line
. With ksh93, yash¹ or recent versions of bash
. IFS=$' \t\r'
would also strip the trailing CR character found in text files from the Microsoft world.
¹ though yash
doesn't support the $'...'
syntax yet, you'd need IFS=$(printf ' \t\r')
there.