# Read a file (data stream, variable) line-by-line (and/or field-by-field)?

# Looping through a file line by line

while IFS= read -r line; do
   echo "$line"
done <file

If file may not include a newline at the end, then:

while IFS= read -r line || [ -n "$line" ]; do
   echo "$line"
done <file

# Looping through the output of a command field by field

Let's assume that the field separator is :

while IFS= read -d : -r field || [ -n "$field" ];do
    echo "**$field**"
done < <(ping google.com)

Or with a pipe:

ping google.com | while IFS= read -d : -r field || [ -n "$field" ];do
    echo "**$field**"
done

# Read lines of a file into an array

readarray -t arr <file

Or with a loop:

arr=()
while IFS= read -r line; do
   arr+=("$line")
done <file

# Read lines of a string into an array

var='line 1
line 2
line3'
readarray -t arr <<< "$var"

or with a loop:

arr=()
while IFS= read -r line; do
   arr+=("$line")
done <<< "$var"

# Looping through a string line by line

var='line 1
line 2
line3'
while IFS= read -r line; do
   echo "-$line-"
done <<< "$var"

or

readarray -t arr <<< "$var"
for i in "${arr[@]}";do
    echo "-$i-"
done

# Looping through the output of a command line by line

while IFS= read -r line;do
    echo "**$line**"
done < <(ping google.com)

or with a pipe:

ping google.com |
while IFS= read -r line;do
    echo "**$line**"
done

# Read a file field by field

Let's assume that the field separator is : (colon) in the file file.

while IFS= read -d : -r field || [ -n "$field" ]; do
   echo "$field"
done <file

For a content:

first : se
con
d:
    Thi rd:
    Fourth

The output is:

**first **
** se
con
d**
**
    Thi rd**
**
    Fourth
**

# Read a string field by field

Let's assume that the field separator is :

var='line: 1
line: 2
line3'
while IFS= read -d : -r field || [ -n "$field" ]; do
   echo "-$field-"
done <<< "$var"

Output:

-line-
- 1
line-
- 2
line3
-

# Read fields of a file into an array

Let's assume that the field separator is :

arr=()
while IFS= read -d : -r field || [ -n "$field" ]; do
   arr+=("$field")
done <file

# Read fields of a string into an array

Let's assume that the field separator is :

var='1:2:3:4:
newline'
arr=()
while IFS= read -d : -r field || [ -n "$field" ]; do
   arr+=("$field")
done <<< "$var"
echo "${arr[4]}"

Output:

newline

# Reads file (/etc/passwd) line by line and field by field

#!/bin/bash
FILENAME="/etc/passwd"
while IFS=: read -r username password userid groupid comment homedir cmdshell
do
  echo "$username, $userid, $comment $homedir"
done < $FILENAME

In unix password file, user information is stored line by line, each line consisting of information for a user separated by colon (😃 character. In this example while reading the file line by line, the line is also split into fields using colon character as delimiter which is indicated by the value given for IFS.

Sample input

mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tomcat:x:91:91:Apache Tomcat:/usr/share/tomcat6:/sbin/nologin
webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin

Sample Output

mysql, 27, MySQL Server /var/lib/mysql
pulse, 497, PulseAudio System Daemon /var/run/pulse
sshd, 74, Privilege-separated SSH /var/empty/sshd
tomcat, 91, Apache Tomcat /usr/share/tomcat6
webalizer, 67, Webalizer /var/www/usage

To read line by line and have the entire line assigned to variable, following is a modified version of the example. Note that we have only one variable by name line mentioned here.

#!/bin/bash
FILENAME="/etc/passwd"
while IFS= read -r line
do
  echo "$line"
done < $FILENAME

Sample Input

mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tomcat:x:91:91:Apache Tomcat:/usr/share/tomcat6:/sbin/nologin
webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin

Sample Output

mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tomcat:x:91:91:Apache Tomcat:/usr/share/tomcat6:/sbin/nologin
webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin

# Parameters

Parameter Details
IFS Internal field separator
file A file name/path
-r Prevents backslash interpretation when used with read
-t Removes a trailing newline from each line read by readarray
-d DELIM Continue until the first character of DELIM is read (with read), rather than newline