Field separators and iterators
The internal field separator (IFS) is an important concept in shell scripting. It is useful for manipulating text data.
An IFS is a delimiter for a special purpose. It is an environment variable that stores delimiting characters. It is the default delimiter string used by a running shell environment.
Consider the case where we need to iterate through words in a string or comma separated values (CSV). In the first case, we will use IFS=" " and in the second, IFS=",".
Getting ready
Consider the case of CSV data:
data="name,gender,rollno,location"
To read each of the item in a variable, we can use IFS.
oldIFS=$IFS
IFS=, # IFS is now a ,
for item in $data;
do
echo Item: $item
done
IFS=$oldIFSThis generates the following output:
Item: name Item: gender Item: rollno Item: location
The default value of IFS is a white-space (newline, tab, or a space character).
When IFS is set as , the shell interprets the comma as a delimiter character, therefore, the $item variable takes substrings separated by a comma as its value during the iteration.
If IFS is not set as , then it will print the entire data as a single string.
How to do it...
Let's go through another example usage of IFS to parse the /etc/passwd file. In the /etc/passwd file, every line contains items delimited by :. Each line in the file corresponds to an attribute related to a user.
Consider the input: root:x:0:0:root:/root:/bin/bash. The last entry on each line specifies the default shell for the user.
Print users and their default shells using the IFS hack:
#!/bin/bash
#Desc: Illustration of IFS
line="root:x:0:0:root:/root:/bin/bash"
oldIFS=$IFS;
IFS=":"
count=0
for item in $line;
do
[ $count -eq 0 ] && user=$item;
[ $count -eq 6 ] && shell=$item;
let count++
done;
IFS=$oldIFS
echo $user's shell is $shell;The output will be as follows:
root's shell is /bin/bashLoops are very useful in iterating through a sequence of values. Bash provides many types of loops.
- List-oriented
forloop:
for var in list;
do
commands; # use $var
done A list can be a string or a sequence of values.
We can generate sequences with the echo command:
echo {1..50} ;# Generate a list of numbers from 1 to 50. echo {a..z} {A..Z} ;# List of lower and upper case letters.
We can combine these to concatenate data.In the following code, in each iteration, the variable i will hold a character in the a to z range:
for i in {a..z}; do actions; done;- Iterate through a range of numbers:
for((i=0;i<10;i++))
{
commands; # Use $i
}- Loop until a condition is met:
The while loop continues while a condition is true, the until loop runs until a condition is true:
while condition
do
commands;
doneFor an infinite loop, use true as the condition:
- Use a
untilloop:
A special loop called until is available with Bash. This executes the loop until the given condition becomes true. Consider this example:
x=0;
until [ $x -eq 9 ]; # [ $x -eq 9 ] is the condition
do
let x++; echo $x;
done