Bash / KSH: Define Delimiter (IFS) While Using read Command

by on July 25, 2012 · 3 comments· last updated at July 25, 2012

How do I can set IFS (internal field separator) while using read command in bash loops?

The IFS variable is used in as the input field separator. If you set IFS to | (i.e. IFS=| ), | will be treated as delimiters between words/fields when splitting a line of input. In the read command, IFS is used to split the line of input so that each variable gets a single field of the input. The default value is . You can print it with the following command:

 
cat -etv <<<"$IFS"
 

In this example, read first and last name using read command and set IFS to a white space:

 
IFS=' ' read -p 'Enter your first and last name : ' first last
echo "Hello, $first $last"
 

Sample outputs:

Enter your first and last name : Vivek Gite
Hello, Vivek Gite

In this example set IFS to | and read data:

 
IFS='|' read domain ip4 ip6 <<< 'google.com|74.125.236.65|2404:6800:4007:801::1008'
echo "$domain has $ip4 IPv4 and $ipv6 IPv6 address."
 

Sample outputs:

google.com has 74.125.236.65 IPv4 and  IPv6 address.

while loop example with IFS and read command

Create a text file (named foo.txt) as follows:
$ cat foo.txt
Sample outputs:

google.com|74.125.236.65|2404:6800:4007:801::1008
i.theos.in|58.27.86.81|2600:807:320:305::3f6e:f648
cyberciti.biz|75.126.153.206|2600:807:320:305::3f6e:f649

Create a bash shell script as follows:

 
#!/bin/bash
_input="foo.txt"
# set IFS (internal field separator) to |
# read file using while loop
while IFS='|' read -r domain ip4 ip6
do
   echo "$domain has $ip4 IPv4 and $ipv6 IPv6 address."
done < "$_input"
 


You should follow me on twitter here or grab rss feed to keep track of new changes.

Featured Articles:

{ 3 comments… read them below or add one }

1 Pierre B. July 25, 2012 at 9:35 pm

Thx Vivek, i use custom IFS sometimes when i do bash scripts, but i’ve never had the idea to include it directly inside the while loop !
That easy, quick, efficient and class, just what i like.

Thx for the tips.

Pierre B.

Reply

2 Pierre B. July 26, 2012 at 8:15 am

Hi Vivek,

I did try to apply this trick to one of my script, but it seems that specifying the IFS this way broke something, when i put it back as it was before : it works again.

Here is the function where i do use the custom IFS :

Log_Chk() {
  # Usage: $0 called with the "log name" as $@ (as a list)
  #+ Note :only the "esmlog" is checked by this function, as it the only relevant log for hardware components status
  DOMAIN="ESMLOG"
  PrintDomainStart ${DOMAIN}
  OLD_IFS=$IFS # backup the default IFS
while read line ; do    # Set IFS to its new value, defined by the "cdv" value
    IFS=";"
    omconfig preferences cdvformat delimiter=semicolon &>/dev/null # Set the "semicolon" as the "cdv"
    read Status Data_or_Date Description <</dev/null
    elif [[ "${Status}" = 'Non-Critical' ]] ; then
      PrintWarning "${Description:0:22}... @ ${Data_or_Date#[[:upper:]][[:alpha:]][[:alpha:]][[:space:]]}" "${Status}" "1" && RETCODE="${NonCritical}" 2>/dev/null
    elif [[ "${Status}" = 'Ok' ]] ; then
      PrintOk "${Description:0:22}... @ ${Data_or_Date#[[:upper:]][[:alpha:]][[:alpha:]][[:space:]]}" "${Status}" "1" # Do nothing !
    fi
  done << EOF
	  $(omreport system esmlog -fmt cdv |tail -10 |grep -E "^(Ok|Non-Critical|Critical)")
EOF
IFS=$OLD_IFS # Back to default IFS
  PrintDomainEnd
  return $RETCODE
}

Reply

3 Pierre B. July 31, 2012 at 2:50 pm

Ok, i finally change that piece of *** i posted for something cleaner, and then it works.
Just in case i post it there :

Log_Chk() {
# Usage: $0 called with the “log name” as $@ (as a list)
#+ Note :only the “esmlog” is checked by this function, as it the only relevant log for hardware components status
if [[ "${ChassisModel}" =~ 'R710' ]] ; then
DOMAIN=”ESMLOG”
log=”esmlog”
else
DOMAIN=”ALERTLOG”
log=”alertlog”
fi
PrintDomainStart ${DOMAIN}

while IFS=”;” read Status Data_or_Date Description ; do
omconfig preferences cdvformat delimiter=semicolon &>/dev/null # Set the “semicolon” as the “cdv”
if [[ "${Status}" = 'Critical' ]] ; then
PrintFailure “${Description:0:24}… @ ${Data_or_Date#[[:upper:]][[:alpha:]][[:alpha:]][[:space:]]}” “${Status}” “1″ && declare -r RETCODE=”${Critical}” 2>/dev/null
elif [[ "${Status}" = 'Non-Critical' ]] ; then
PrintWarning “${Description:0:24}… @ ${Data_or_Date#[[:upper:]][[:alpha:]][[:alpha:]][[:space:]]}” “${Status}” “1″ && RETCODE=”${NonCritical}” 2>/dev/null
elif [[ "${Status}" = 'Ok' ]] ; then
PrintOk “${Description:0:24}… @ ${Data_or_Date#[[:upper:]][[:alpha:]][[:alpha:]][[:space:]]}” “${Status}” “1″
fi
done <<<"$(omreport system "${log}" -fmt cdv |tail -10 |grep -E "^(Ok|Non-Critical|Critical)" |tac)"

PrintDomainEnd
return $RETCODE
}

Reply

Leave a Comment

You can use these HTML tags and attributes for your code and commands: <strong> <em> <ol> <li> <u> <ul> <kbd> <blockquote> <pre> <a href="" title="">

Tagged as: , , ,

Previous Faq:

Next Faq: