Ksh Read a File Line By Line ( UNIX Scripting )

by on November 20, 2009 · 14 comments· LAST UPDATED December 5, 2009

in , ,

How do I read a file line by line using KSH shell scripting under UNIX like operating systems?

You can use the while loop and read command to read a text file line by line under KSH.

KSH read while loop syntax

# while loop
while read line
        # display line or do somthing on $line
	echo "$line"
done <"$file"

In this example, you are reading file separated by | fields. Sample domains.txt:

# set the Internal Field Separator to a pipe symbol
# file name
# use while loop to read domain and ip 
while read domain ip
	print "$domain has address $ip"
done <"$file"

However, following is recommend syntax to set the Internal field separator (see discussion below):

# file name
# use while loop to read domain and ip 
# set the Internal Field Separator to a pipe symbol
while IFS=\| read domain ip
	print "$domain has address $ip"
done <"$file"

Suggested readings:

  • ksh man page

Updated for accuracy!

TwitterFacebookGoogle+PDF versionFound an error/typo on this page? Help us!

{ 14 comments… read them below or add one }

1 Daniel J. Doughty November 20, 2009 at 5:00 pm

Thanks, I usually don’t like doing my heavy lifting with shell scripting. Still, this is useful information because sometimes the shell is all you have in the environment you’re working in.



2 Joel November 20, 2009 at 10:15 pm

Thanks for the scripting tips, they really are the key to effective system administration tasks. The differences between the shells is new to me, I usually just use bash since it’s the default on the systems I use. I looked up the Korn shell on Wikipedia and it reports that it has backwards compatibility to the Bourne shell (which is Bash’s predecessor). On my system I did an experiment to see if the scripts would work with Bash and changed the #!/bin/ksh to #!/bin/sh. The first one works find, the second doesn’t – looks like it doesn’t support the “IFS” environment label. Interesting.

Now, if someone can explain the different between this alphabet soup and sym links that would be helpful (Ubuntu 8.04.1). Never heard of ‘dash’!

-rwxr-xr-x 1 root root 702160 May 12 2008 /bin/bash
-rwxr-xr-x 1 root root 79988 Mar 12 2008 /bin/dash
lrwxrwxrwx 1 root root 21 Nov 20 14:05 /bin/ksh -> /etc/alternatives/ksh
lrwxrwxrwx 1 root root 4 Apr 24 2008 /bin/sh -> dash


3 Shantanu Oak November 21, 2009 at 5:37 am

When there are a few lines to be read, I do always use the following method.

while read line
echo “$line”
done << iplist


4 nixCraft November 21, 2009 at 9:44 am


The original sh is not available under Linux. dash is the standard command interpreter for the system. The current version of dash is in the process of being changed to conform with the POSIX 1003.2 and 1003.2a specifications for the shell. This version has many features which make it appear similar in some respects to the Korn shell, but it is not a Korn shell clone.

/etc/alternatives/ksh should point to to ksh93. Run the following

ls -l /etc/alternatives/ksh

sym links allows to use different version of ksh without breaking anything. update-alternatives command maintain symbolic links determining default commands for various system commands, and java. See man page

man ksh
man dash
man update-alternatives


5 Philippe Petrinko November 21, 2009 at 12:33 pm

dash is standard shell under UBUNTU,
(and should have been under Debian Lenny)


6 Brock Noland November 24, 2009 at 10:27 pm

Thanks for making people aware of native shell string splitting, but I would reset IFS.


7 Chris F.A. Johnson November 30, 2009 at 2:41 pm

The safe way to change IFS in a ‘while read’ loop is:

while IFS=\| read a b c
: whatever

Then it doesn’t affect anything but the read command.


8 Philippe Petrinko November 30, 2009 at 5:19 pm

To Chris : short and simple – How nice!
Should have think of this good old shell syntax
Good example of KISS principle … (ask Wikipedia)


9 ishan February 24, 2012 at 6:49 am

while reading line by line like this if you want to take user desire input
eg :-
cat use |while read mo
read -r o
if [[ $o = ‘y’ ]]
print “$mo”
print “kill me”

In this case o/p will be always kill me …….user input wouldn’t be there so …..how to take user input in that


10 Philippe Petrinko February 24, 2012 at 11:35 am


Solution is to separate user input from data input.
Use Vivek’s tutorial:

A solution may be:

# File descriptor #0 is stdin
# File descriptor #1 is stdout
# File descriptor #2 is stderr
# Let us assign extra file descriptor to file for input
# open for input file named "data" with fd #3
exec 3< data
# loop on fd #3
while read <&3
	# ask user input, by default on stdin
	read -p "Print next line of data ? (y/n):" answer
	# to debug, uncomment the following line
	# echo "Answer:${answer}:"
	# branch on answer, casted to lowercase
	if [[ "${answer,,}" = 'y' ]]
		# user wants to see data
		# which is by default read in builtin REPLY variable
		echo $REPLY
		# user wants to quit
		# let us terminate while loop
# Close fd #3
exec 3<&-

HTH, Try it and let us know your solution.

— Philippe


11 Prashanth February 14, 2014 at 11:22 am

Dear Experts,
I have a scenario where in
we need read file (.csv) row by row and
Select the value for the column “Q2014″.
which further segregated into (Q1 2014 ,Q2 2014,Q3 2014,Q4 2014) we need to get the Sum Q1 2014 for all products.
If the Sum(Q1 2014 ) > sum(Q2 2014) if the difference is > 5% then send a mail.
Your help in highly appreciable.

Thanks in Advance,


12 Mike S March 12, 2014 at 4:14 pm

This is probably better handled by an application than a Korn shell script, but it sounds like an interesting challenge, so here goes.
First, it isn’t clear to me from your question how your .csv file is formatted, but I’m going to assume the following:

Q1 2013,Q2 2013,Q3 2013,Q4 2013,Q1 2014,Q2 2014

If your CSV file has a different format, you should be able to modify the solution below to match it.

let linenum=1
let col1=-1
let col2=-1
let sum1=0
let sum2=0
while read fline
  set -A farray $fline
  let numcols=${#farray[*]}
  if [[ $linenum -eq 1 ]]; then
    for (( x=1 ; $x <= $numcols ; x+=1 ))
      if [[ $farray[x] == "Q1 2014" ]]; then
        let col1=$x
      if [[ $farray[x] == "Q2 2014" ]]; then
        let col2=$x
    if [[ $col1 -eq -1 || $col2 -eq -1 ]]; then
      echo 'One or both column headers not found'
      exit 1
    let sum1+=${farray[$col1]}
    let sum2+=${farray[$col2]}
  let linenum+=1
done < "datafile.csv"
# (I'm assuming sum1 is the basis for the 5%)
let delta=$sum1-$sum2
let delta*=20
if [[ $delta -ge $sum1 ]]; then
  echo 'Send an email notification'

Obviously, the echo statement would be replaced by whatever you use to send an email from the script. I've also hardcoded the filename and column header strings for simplicity, but I assume you'd make those values script inputs.
This works for me, but I might have missed something (I'm not a scripting expert by any means) so comments/corrections from experts are welcomed.

Edited by mods


13 Mike S March 12, 2014 at 4:19 pm

Oops – mis-copied part of the script!

done  sum1

Should have been

done < "datafile.csv"


14 vignesh April 14, 2014 at 2:47 am

could any one please tell me how to declare sql statement inside ‘do’ and get output in a text



Leave a Comment

Tagged as: , , , , , , , , , , , , , ,

Previous Faq:

Next Faq: