Linux/UNIX: Bash Read a File Line By Line

How do I read a text file line by line under a Linux or UNIX-like system using KSH or BASH shell? How do I read a file line by line in bash script?

You can use bash loop to read file line by line on a Linux, OSX, *BSD, or Unix-like system.

Syntax: Read file line by line on a Bash Unix & Linux shell:

Tutorial details
Difficulty level Easy
Root privileges No
Requirements Bash/ksh/zsh/tcsh
Est. reading time 10m
  1. The syntax is as follows for bash, ksh, zsh, and all other shells to read a file line by line
  2. while read -r line; do COMMAND; done < input.file
  3. The -r option passed to read command prevents backslash escapes from being interpreted.
  4. Add IFS= option before read command to prevent leading/trailing whitespace from being trimmed -
  5. while IFS= read -r line; do COMMAND_on $line; done < input.file

How to Read a File Line By Line in Bash

Here is more human readable syntax for you:

while IFS= read -r line
  echo "$line"
done < "$input"

The input file ($input) is the name of the file you need use by the read command. The read command reads the file line by line, assigning each line to the $line bash shell variable. Once all lines are read from the file the bash while loop will stop. The internal field separator (IFS) is set to the empty string to preserve whitespace issues. This is a fail-safe feature.

How to use command/process substitution to read a file line by line

Process or command substitution means nothing more but to run a shell command and store its output to a variable or pass it to another command. The syntax is:

while IFS= read -r line
   ## take some action on $line
  echo "$line"
done < < (command)
while IFS= read -r line
   ## take some action on $line
  echo "$line"
done < <(ps aux)

Using a here strings

Here strings is just like here documents:

while IFS= read -r line
  # take action on $line #
  echo "$line"
done <<< $(command)
while IFS= read -r line
  # take action on $line #
  echo "$line"
done <<< $(ps aux)
## shell script to purge urls from Cloudflare ##
while IFS= read -r line
        url="$url $line"
done <<<"$(tail -${t} ${I})"
[ "$url" != "" ] && ~/bin/ "$url"

How to file descriptor with read command

The syntax is simple:

while IFS= read -r -uN line
  # do something on $line
  echo "$line"
done N< $input

Here is a sample script:

while IFS= read -r -u13 line
   echo "$line"
done 13<"${input}"
Bash Read a File Line By Line demo

Examples that shows how to read file line by line

Here are some examples:

while IFS= read line
        # display $line or do something with $line
	echo "$line"
done <"$file"

The same example using bash shell:

while IFS= read -r line
        # display $line or do somthing with $line
	printf '%s\n' "$line"
done <"$file"

You can also read field wise:

while IFS=: read -r f1 f2 f3 f4 f5 f6 f7
        # display fields using f1, f2,..,f7
        printf 'Username: %s, Shell: %s, Home Dir: %s\n' "$f1" "$f7" "$f6"
done <"$file"

Sample outputs:

Fig.01: Bash shell scripting-  read file line by line demo outputs

Fig.01: Bash shell scripting- read file line by line demo outputs

Bash Scripting: Read text file line-by-line to create pdf files

My input file is as follows (faq.txt):

4||Mysql User Creation: Setting Up a New MySQL User Account
4096||What is UNIX / Linux Korn Shell?
4101||What Is POSIX Shell?
17267||Linux: Check Battery Status Command
17245||Linux Restart NTPD Service Command
17183||Ubuntu Linux: Determine Your IP Address
17172||HowTo: Determine an IP Address My Linux Server
16510||Linux / Unix: Restart PHP Service Command
8292||FreeBSD: Mount Hard Drive / Disk Command
8190||Reboot a Solaris UNIX System

My bash script:

# Usage: Create pdf files from input (wrapper script)
# Author: Vivek Gite <> under GPL v2.x+
#Input file
#Output location
# If file exists 
if [[ -f "$_db" ]]
    # read it
	while IFS='|' read -r pdfid pdfurl pdftitle
    	local pdf="$o/$pdfid.pdf"
        echo "Creating $pdf file ..."
	#Genrate pdf file
        $_writer --quiet --footer-spacing 2 \
        --footer-left "nixCraft is GIT UL++++ W+++ C++++ M+ e+++ d-" \
        --footer-right "Page [page] of [toPage]" --footer-line \
        --footer-font-size 7 --print-media-type "$pdfurl" "$pdf"
    done <"$_db"

Read from bash shell variable

Let us say you want a list of all installed php packages on a Debian or Ubuntu Linux, enter:

# My input source is the contents of a variable called $list #
list=$(dpkg --list php\* | awk '/ii/{print $2}')
printf '%s\n' "$list"

Sample outputs:


You can now read from $list and install the package:

# BASH can iterate over $list variable using a "here string" #
while IFS= read -r pkg
    printf 'Installing php package %s...\n' "$pkg"
    /usr/bin/apt-get -qq install $pkg
done <<< "$list"
printf '*** Do not forget to run php5enmod and restart the server (httpd or php5-fpm) ***\n'

Sample outputs:

Installing php package php-pear...
Installing php package php5-cli...
Installing php package php5-common...
Installing php package php5-fpm...
Installing php package php5-gd...
Installing php package php5-json...
Installing php package php5-memcache...
Installing php package php5-mysql...
Installing php package php5-readline...
Installing php package php5-suhosin-extension...
*** Do not forget to run php5enmod and restart the server (httpd or php5-fpm) ***


This page explained how to read file line by line in bash shell script.

🐧 Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or Weekly email newsletter.

🐧 24 comments so far... add one

CategoryList of Unix and Linux commands
Disk space analyzersncdu pydf
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network UtilitiesNetHogs dig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04
24 comments… add one
  • Chris F.A. Johnson Feb 8, 2011 @ 18:42

    The bash example is correct for all shells. The ksh example is not correct; it will strip leading and trailing whitespace.

    To demonstrate, use:

    echo ":$line:"

    on a file with leading and/or trailing whitespace on one or more .

    • tom Sep 15, 2017 @ 4:38

      The BASH password file parsing example does not work for my centos 7 box: all the colons are stripped from each line and the whole line without colons is stored in f1
      my output reads:
      Username: root/root/bin/bash, Home directory: , Shell:

  • Anthony Thyssen Sep 14, 2011 @ 23:35

    Reading a file line by line with a single loop is fine in 90% of the cases.

    But if things get more complicated then you may be better off opening the file as a file descriptor.

    Situations such as:

    * the read of the file is only a minor aspect and not the main task, but you want to avoid opening an closing the file multiple times. For example preserving where you have read up to or avoiding file closure (network, named pipes, co-processing)

    * the file being read requires different methods of parsing, that is better done in simpler but different loops. Reading emails (header and body) is an example of this, but so is reading files with separate operational and data blocks.

    * you are reading from multiple files at the same time, and switching between different files, in a pseudo-random way. That is you never quite know whch file you will need to read from next.

  • princess anu Apr 4, 2012 @ 19:01

    I have a scenario like this. I have a file which has servername, port and ipaddress

    I tried couple of ways reading these records and assigning them a field and print the output to a file like below but nothing is helpful

    servername port ipaddress
    svr1 port1 ip1
    scr2 port2 ip2
    and so on

    can someone please help me.


  • princess anu Apr 5, 2012 @ 15:20

    I figured it out. May be not professional but it is working for me.

    echo -n "server name    "
    echo "port number"
    echo "-----------------------------------------"
    while read line
    echo -n "$line        "
    i=$(($num % 2 ))
    if [ $i -eq 0 ]
    echo "" #### print the new line ###
    num=`expr $num + 1`
    done< serverlist.txt


    • jl3128 Aug 25, 2015 @ 22:18

      if the file is 100% predictable in each host,ip,port coming in groups of 3 you can use “paste”

      cat list.txt | paste – – –

  • Robert Edward Johnson Jun 10, 2012 @ 2:30


    I have a question concerning how you’d actually process individual fields of input.
    For example, let’s say you’re doing the usual

    while read LINE; do
    process the statements
    done firstbyteinq and looking at firstbyteinq with a read, but 1). the cut doesn’t seem to be doing it just to the record being read, it does it to ALL the records all at one time; 2). the read of the firstbyteinq then advances the other file one record!!!

    It seems to me there ought to be some way to “declare” the positions from a to b as fields and THEN use the while read, but I’m not sure how to do that.
    I’ll try anything. Thanks VERY much in advance.

  • Chris F.A. Johnson Jun 10, 2012 @ 16:16

    princess anu, there’s no need to use arithmetic; just read the file in groups of three lines:

    while :
      read server
      read port
      read ipaddr
      : do whatever
    done < "$file"
  • Chris F.A. Johnson Jun 10, 2012 @ 16:28

    A correction; you need to check that the read succeeded; checking the first should be enough:

    while :
      read server || break
      read port
      read ipaddr
      : do whatever
    done < "$file"
  • MAYANK Sep 6, 2012 @ 8:19

    I have scenario :

    One file which contain values like:

    another file is template which has to use values from 1st file (One value at a time, line by line )

    ARGS=ABS >> save in one file

    New file:
    ARGS=SVS >> save in another file

    Can you please help me to achive this

    • bhupesh May 14, 2014 @ 6:30

      u can use paste command if the fields are same …..and then output the records to the other file and print another.

      • bhupesh May 14, 2014 @ 6:56

        rm 3 4 5
        cat 1 | while read l
        echo “$l =” >> 3
        paste 3 2 | while read line
        echo “$line” >> 4
        awk ‘{print $1,$2,$3}’ 4 > 5

        now u can move the records line by line to another file

  • Name Jul 2, 2013 @ 13:35

    echo “$line” # <— will fail if "$line" is "-n", it won't print anything at all, even an empty line.

    You should use printf builtin to work around this behavior:
    printf "%s\n" "$line"

  • Chris F.A. Johnson Jul 3, 2013 @ 11:40

    Some shells shells will output -n; that is what POSIX requires.

  • Steve Jan 28, 2014 @ 0:55

    My while/read is having an issue with the data not being printed for the last line read.
    The info is read and summed but is not being printed to the report.
    The script is reading a file with tab delimited fields, sorting on a field then reading each line while assigning the fields to var names.
    If statements determine whether the numbers are summed or if a new category is found with the previous categories data being written to the report. All categories except the last are complete in the report. The last category is left out.
    I added trouble shooting echo statements to check the workflow and they showed that the last category is being read and summed but it doesnt get printed.
    It’s as if the read gets to the last line, does the work and then doesnt know what to do with the output.
    The sorted data looks something like:

    247   an-IP   Name1
    37   another-IP   Name1
    52    more-IPs   Name2
    1562   etc   Name2
    29   etc   name3
    4   etc   name3
    The report has:
    284 Name1
    1591 Name2

    Code with troubleshooting echos and most comments deleted:

    #control vars
    cat  | sort -k3 | while read -r Count IP Name
    # Handle the first line
       if [ "Name" != "$name" -a $GT -eq 0 ]
    # The read name is different than the last line (new category)
       elif [ "$Name != $name" -a $GT -gt 0 ]
    # Write previous name and count to the report
          echo " ${name} - ${GT}" >> 
    # Assign new categories values to the vars
    # New line but same category found
       else [ "$Name" == "$name"  ]
    # Increment counts of the category
          GT=`expr $GT + $Count`
  • name Apr 3, 2014 @ 9:45

    The read name is different than the last line (new category)

       elif [ "$Name != $name" -a $GT -gt 0 ]
    # Write previous name and count to the report
          echo " ${name} - ${GT}" >>
    # Assign new categories values to the vars
    # New line but same category found
       else [ "$Name" == "$name"  ]
    # Increment counts of the category
          GT=`expr $GT + $Count`
  • Chris F.A. Johnson May 14, 2014 @ 11:25


    cat | sort -k3 | while read -r Count IP Name

    is the same as

    sort -k3 | while read -r Count IP Name

  • Stephane Aug 26, 2015 @ 6:47

    It is also possible to store the elements in a bash array using the -a option

    The following example reads some comma separated values and print them in reverse order:

    while IFS="," read -a A ; do 
       for ((i=${#A[@]}-1;i>=0;i--)) ; do 
         echo -n "$SEP${A[i]}"  
    done < input.txt
  • Jaquice Stone Sep 23, 2015 @ 13:52

    Hi guys. I’m just getting started with scripting and I am needing some help reading a file into the script. This shell script below works and does what it needs to do but I have to manually input the file name for “read list”. How do I modify this script to automatically read the file. Inside the file is just a list of aix server names.

    echo ” Please input the master list you know to use”
    read list
    for i in `cat $list`
    ssh $i hostname
    ssh $i df

  • Tory Nov 5, 2015 @ 18:34

    Hi all,
    I need to write a script to look for user in /etc/passwd file. The program takes user input from command line and check to see if the user that the person entered exists. If user doesn’t exist, the script sends error message. I use grep to print the user which exist. But not sure what command to use and look and if the user doesn’t exist, send error message?

  • Hari Dec 15, 2015 @ 11:25

    Hi stone,
    me trying to get the list of server have /mysqlshare file system in it but i am unable to get it..
    for now trying get only 2 server details from txt file ie(text.txt) which have
    when i try this script its only reading 1st server details and getting exit from script

    # while loop
    while IFS= read -r a
            # display line or do somthing on $line
            output=`ssh $a df -h | grep mysqlshare`
    #echo $a,$output
    echo $a ,$output >>/home/mysqladm/server_list/output.txt
    done <"$file"

    Can someone help me out..

  • Jaison V John Aug 1, 2017 @ 15:38

    Thanks man!

  • Eyang Naga Sep 26, 2020 @ 10:57

    can anyone help me to include the line number while read line by line ,

    # cat file.txt

    my desire output is

    1. mike
    2. vero
    3. james

    thank you before

    • r00t Oct 19, 2020 @ 7:03

      cat file.txt | nl
      I see

           1  mike
           2  vero
           3  james

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre> for code samples. Still have questions? Post it on our forum