Q1How does while read line; do … done < file process file?
Reading Input — Handling a File Line by Line with while read
This article is part of the Linux Course, where you master practical Linux skills from scratch, from basic commands through to shell scripting.
Process data.txt line by line and split it into columns with while read name age, handle multiple files passed as arguments in order with for f in "$@", and feed read input via pipes or here-docs — illustrated and practiced in a browser terminal.
Reading a file line by line — while read
You often want to process a roster or config file one line at a time.
When you write while read line; do … done < file, it reads file from the top one line at a time, puts that line into the variable line, and repeats the body between do … done.
No matter how many lines the file has, it loops automatically all the way to the last line.
read splits the line it receives on whitespace and can put the pieces into several variables.
When you write while read name age; do …, the first word of each line goes into name and the next word into age.
For data laid out as "name value" like a roster, you can pull out each column and reformat it.
printf 'web running\ndb stopped\n' > services.txt # create the sample file
while read svc state; do # read each line into svc and state
echo "Service $svc is $state"
done < services.txt # feed services.txt as input
# output: Service web is running / Service db is stopped
while read name age reads a file one line at a time and, splitting on whitespace, puts the first word into name and the next into age.| Syntax | Meaning | Example |
|---|---|---|
while read v; do … done < f | Process file f one line at a time with variable v | while read l; do echo "$l"; done < data.txt |
while read a b; do … | Split a line on whitespace into several variables | while read name age; do echo "$name"; done < data.txt |
Receiving multiple files as arguments — "$@" and $(cat f)
If you hardcode the filename to process inside the script, you can't use it on another file.
When you pass them at run time like ./show.sh a.txt b.txt, $1 becomes the first and $2 the second argument.
You can receive all the arguments together with "$@".
When you write for f in "$@"; do … done, you can put each passed file into f one at a time and process them in order.
When you want to use the whole file as a single string, pull it into a variable with text=$(cat "$f").
You get the number of arguments with $#, so you can make it show usage when there are 0.
printf 'line A1\nline A2\n' > a.txt # sample file 1
printf 'line B1\n' > b.txt # sample file 2
vi show.sh # open in the editor, write the following, and save with :wq
# #!/bin/sh
# for f in "$@"; do
# echo "--- $f ---"
# cat "$f"
# done
chmod +x show.sh
./show.sh a.txt b.txt # show 2 files in order with headers
$1 and $2, and with "$@" you receive them together and process them one at a time with for.| Syntax | Meaning | Example |
|---|---|---|
for f in "$@"; do … | Process each argument file in order | for f in "$@"; do cat "$f"; done |
$(cat f) | Pull the whole file into a single string | text=$(cat data.txt) |
$# | The number of arguments (show usage if 0) | [ "$#" -eq 0 ] && echo usage |
Interactive input and pipe input — read and here-doc
read can read not only files but also input typed by a person or passed through a pipe.
There are forms like connecting with a pipe as in echo hi | read v, and feeding input on the spot all at once with a <<'EOF' … EOF here-doc.
This is the basis for combining your script with other commands.
# read a pipe's output one line at a time
printf 'one\ntwo\n' | while read v; do echo "line: $v"; done
# feed input on the spot with a here-doc
while read v; do echo "value: $v"; done <<'EOF'
x
y
EOF
# read manual input once (type name and press Enter)
# running this waits for input
read name; echo "Hello $name"
while read input one line at a time with a pipe or a here-doc.| Syntax | Meaning | Example |
|---|---|---|
cmd | while read v; do … | Process a pipe's output one line at a time | cat data.txt | while read l; do echo "$l"; done |
<<'EOF' … EOF | Feed input on the spot with a here-doc | while read l; do echo "$l"; done <<'EOF' |
Knowledge Check
Answer each question one by one.
Q2Which notation represents all the arguments passed to the script together?
Q3How do you process a command's output one line at a time with read, without creating a file?