- Using «while read. » in a linux script
- 2 Answers 2
- Different Ways to Read File in Bash Script Using While Loop
- Piping in Linux
- Input Redirection in Linux
- Internal Field Separator
- Empty Lines in Linux
- Escape Characters
- Bash: while read line
- Basic Syntax of while read line
- Example # 1: File Reading line by line
- Example # 2: Reading file using the bash script
- Alternative Method for file reading
- Using passing file name from a command
- Conclusion
- About the author
- Karim Buzdar
- Sysadminium
Using «while read. » in a linux script
Specifically, I’d like to know why the output of this loop is 3 4 5 6 2 1 , instead of 3 2 1 and 6 5 4 on two separate lines? I can’t seem to wrap my mind around it.
2 Answers 2
read reads a whole line from standard input, splits the line into fields and assigns this fields to the given variables. If there are more pieces than variables, the remaining pieces are assigned to the last variable.
In your case $a is assigned 1 , $b is assigned 2 and $c the remaining 3 4 5 6 .
Thanks Florian! Now it makes sense. For some reason I thought spaces would delimit each variable reading, but apparently not. I appreciate your help!!
Rewriting the loop this way reveals what is happening:
echo '1 2 3 4 5 6' | while read a b c do echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)' done
(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)
Notice first that only a single echo command is run. If it were run more than once, you would, among other things, see the (iteration beginning) and (iteration ending) substrings printed more than once.
This is to say that having a while loop here is not really accomplishing anything. The read builtin reads whitespace-separated text 1 into each specified variable. Extra input gets appended to the end of the last variable specified. 2 Thus variables a and b take on the values 1 and 2 respectively, while c takes on the value 3 4 5 6 .
When the loop condition ( while read a b c ) is evaluated the second time, there’s no more input available from the pipe (we only piped it a single line of text), so the read command evaluates to false instead of true and the loop stops (before ever executing the body a second time).
1: To be technical and specific, the read builtin, when passed variable names as arguments, reads input, splitting it into separate «words» when it encounters IFS whitespace (see also this question and this article).
2: read ‘s behavior of jamming any extra fields of input into the last variable specified is nonintuitive to many scripters, at first. It becomes easier to understand when you consider that, as Florian Diesch’s answer says, read will always (try to) read a whole line—and that read is intended to be usable both with and without a loop.
Different Ways to Read File in Bash Script Using While Loop
This article is all about how to read files in bash scripts using a while loop. Reading a file is a common operation in programming. You should be familiar with different methods and which method is more efficient to use. In bash, a single task can be achieved in many ways but there is always an optimal way to get the task done and we should follow it.
Before seeing how to read file contents using while loop, a quick primer on how while loop works. While loop evaluates a condition and iterates over a given set of codes when the condition is true.
while [ CONDITION ] do code block done
Let’s break down while loop syntax.
- while loop should start with a while keyword followed by a condition.
- A condition should be enclosed within [ ] or [[ ]]. The condition should always return true for the loop to be executed.
- The actual block of code will be placed between do and done.
NUMBER=0 while [[ $NUMBER -le 10 ]] do echo " Welcome $ times " (( NUMBER++ )) done
This is a very simple example, where the loop executes until NUMBER is not greater than 10 and prints the echo statement.
Along with while we will use the read command to read the contents of a file line by line. Below is the syntax of how while and read commands are combined. Now there are different ways to pass the file as input and we will see them all.
# SYNTAX while read VARIABLE do code done
Piping in Linux
Normally we will use the cat command to view the contents of the file from the terminal. Also, we will pipe the output of the cat command to other commands like grep, sort, etc.
Similarly, we will use the cat command here to read the content of the file and pipe it to a while loop. For demonstration, I am using /etc/passwd file but it is not advisable to mess with this file so take a backup copy of this file and play with it if you desire so.
cat /etc/passwd | while read LREAD do echo $ done
Let’s break down what will happen when the above code is submitted.
- cat /etc/passwd will read the contents of the file and pass it as input through the pipe.
- read command reads each line passed as input from cat command and stores it in the LREAD variable.
- read command will read file contents until EOL is interpreted.
You can also use other commands like head, tail, and pipe it to while loop.
head -n 5 /etc/passwd | while read LREAD do echo $ done
Input Redirection in Linux
We can redirect the content of the file to while loop using the Input redirection operator (<) .
while read LREAD do echo $ done < /etc/passwd | head -n 5
You can also store the file name to a variable and pass it through a redirection operator.
FILENAME="/etc/passwd" while read LREAD do echo $ done
You can also pass file names as an argument to your script.
while read LREAD do echo $ done < $1 | head -n 5
Internal Field Separator
You may work with different types of file formats (CSV, TXT, JSON) and you may want to split the contents of the file based on a custom delimiter. In this case, you can use “Internal field separator (IFS)” to split the content of the file and store it in variables.
Let me demonstrate how it works. Take a look at the /etc/passwd file which has a colon (:) as the delimiter. You can now split each word from a line and store it in a separate variable.
In the below example, I am splitting /etc/passwd file with a colon as my separator and storing each split into different variables.
while IFS=":" read A B C D E F G do echo $ echo $ echo $ echo $ echo $ echo $ echo $ done < /etc/passwd
I displayed just one line split in the above screenshot considering screenshot size.
Empty Lines in Linux
Empty lines are not ignored when you loop through the file content. To demonstrate this I have created a sample file with the below content. There are 4 lines and few empty lines, leading whitespace, trailing white space, tab characters in line 2, and some escape characters (\n and \t).
while read LREAD do echo $ done < testfile
See the result, blank line is not ignored. Also, an interesting thing to note is how white spaces are trimmed by the read command. A simple way to ignore blank lines when reading the file content is to use the test operator with the -z flag which checks if the string length is zero. Now let’s repeat the same example but this time with a test operator.
while read LREAD do if [[ ! -z $LREAD ]] then echo $ fi done < testfile
Now from the output, you can see empty lines are ignored.
Escape Characters
Escape characters like \n , \t , \c will not be printed when reading a file. To demonstrate this I am using the same sample file which has few escape characters.
while read LREAD do echo $ done < testfile
You can see from the output escape characters have lost their meaning and only n and t are printed instead of \n and \t . You can use -r to prevent backslash interpretation.
while read -r LREAD do echo $ done < testfile
That’s it for this article. We would love to hear back from you if there are any feedbacks or tips. Your feedback is what helps us to create better content. Keep reading and keep supporting.
Bash: while read line
When you are working on bash scripts, sometimes you may need to read a file line by line. Let’s explain with an example. You have some data in a text file that should be executed or processed by using a script. So, running a bash script to process a text file is much different. You need to follow a specified syntax to read a file line by line. This article will help you to read a line from a file using the while loop in Bash.
Basic Syntax of while read line
The following syntax is used for bash shell to read a file using while loop:
The option ‘-r’ in the above-mentioned syntax passed to read command that avoids the backslash escapes from being interpreted. The ‘input_file’ option has represented the name of your file that you want to access by using the ‘read’ command.
The internal field separator abbreviated as IFS can be used before the read command is set to the null string that prevents leading or trailing whitespace from being trimmed.
Open the terminal using ‘Ctrl + Alt + t’ shortcut and then run the following commands on it.
Example # 1: File Reading line by line
Let’s take an example in which suppose we have a file named ‘OS.txt’ containing the names of all important Linux distributions. If you want to read a file without using the ‘cat’ command then, for this purpose you can execute the following command to perform the particular task. We will use the while loop that will read each line from the file ‘OS.txt’ and stores the content in each step in a variable $line that you can display later.
Paste the following names of Linux distributions in the ‘OS.txt’
From the above command, you will get the following response on the terminal window:
Example # 2: Reading file using the bash script
Create a bash file and then add the below-mentioned code in this file to read the file content. You can store the previous text file into a new variable $filename and variable $n is used to keep the value of each line. Now, using the while loop we will read each line from a file with a particular line number.
#!/bin/bash
filename = 'OS.txt'
n = 1
while read line;
do
# for read each line
echo "OS distribution line no. $n : $line "
n =$ ( ( n+ 1 ) )
done < $filename
Save the file with a name ‘OSinfo.sh’ and type the following command on the terminal to run the above bash script.
Now, run the cat command to view the original file content.
Alternative Method for file reading
Using passing file name from a command
In a bash file, you need to add the following code script. In this script, we have to take a filename as an argument. First, the value of an argument is read by a $1 variable which has a filename for reading. It will check that filename exists at the specified location then using the while loop it read a file line by line similar to the previous example.
#!/bin/bash
filename = $1
if [ [ ! -f $filename ] ] ; then
echo "Error, you must enter a filename as a command line parameter"
exit
fi
while read line; do
# reading each line
echo $line
done < $filename
Save the above script with named ‘Readline.sh’ and execute the following command on the terminal to run the above-mentioned script:
You can see the parameter was used as $filename, and read line by line with the while read line syntax from the parameter supplied on the command line.
Conclusion
In this article, we have discussed how to read lines using the while loop in bash programming. We have implemented different methods using the bash script or you can simply use a text file to perform reading a file line by line task. If you are interested to learn more examples then using the above-mentioned syntax you can execute on your system as well. I hope you enjoyed this tutorial and would unique for you. Let’s know in case of any error.
About the author
Karim Buzdar
Karim Buzdar holds a degree in telecommunication engineering and holds several sysadmin certifications. As an IT engineer and technical author, he writes for various web sites. He blogs at LinuxWays.
Sysadminium
В этой статье разберемся с одним из циклов bash, а именно с циклом «while read line». С его помощью будем обрабатывать строки.
Допустим в скрипте есть переменная, значение которой состоит из нескольких строк:
#!/bin/bash a="шишка\nяблоко\nлисток\nгруша" echo -e $a
Напомню, что \n это символ новой строки.
Выполним этот скрипт и получим такой результат:
$ ./test.sh шишка яблоко листок груша
Теперь изменим этот скрипт, чтобы каждая строка обрабатывалась в цикле:
#!/bin/bash a="шишка\nяблоко\nлисток\nгруша" echo -e "$a" | while read line do echo "На дереве висит $line" done
Выполнив этот скрипт получим:
$ ./test.sh На дереве висит шишка На дереве висит яблоко На дереве висит листок На дереве висит груша
Подобный скрипт можно написать и таким способом:
#!/bin/bash echo -e "шишка\nяблоко\nлисток\nгруша" | while read line do echo "На дереве висит $line" done
Таким образом мы можем делать примерно такое:
"команда, возвращающая строки" | while read line do команда которой передаем на обработку каждую строку $line done
Вот еще один пример bash скрипта:
#!/bin/bash cat /etc/passwd | cut -f 1 -d ":" | while read line do echo "В системе есть пользователь - $line" done
$ ./test.sh В системе есть пользователь - root В системе есть пользователь - daemon В системе есть пользователь - bin **** И так далее ***
Также для подобной задачи подходит другой цикл «for line in `comand`», о нём я писал в этой статье.
В этой статье разберемся с одним из циклов bash, а именно с циклом «while read line». С его помощью будем обрабатывать строки