Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read line by line from standard input Bash [duplicate]

Tags:

bash

unix

stdin

I'm studying bash language and an exam track says this:

It should read one input (from standard input) at a time (each entry is a string and then ends with a newline).

My questions are two:

  1. How do I read line by line from standard input in Bash? Until now I used "read string" but I do not think that it reads a line at a time.

  2. I do not know if this is a stupid question , but once created the script how can I give more lines to the script as input (read from standard input of course). For example from stdin I insert two lines (hello and world). How do I give to the bash script these two lines?

like image 716
mario razzu Avatar asked Jul 04 '15 07:07

mario razzu


2 Answers

  1. How do I read line by line from standard input in Bash? Until now I used "read string" but I do not think that it reads a line at a time.

The prototype for read is:

read [options] name[s ...]

read will read a line of input into name name1 name2 ... splitting the line based on the contents of the Internal Field Separator (IFS). The default for IFS is ' \t\n' (that is space tab newline). If you only provide a single variable to read, you will read the entire line into that variable (unless you have set a new delimiter with the -d option to read). If you provide more than one variable, (e.g. read -r name name1) word splitting will occur based on the current value of IFS. Meaning if you provide the string hello world to:

read -r name

name="hello world". On the other hand, if you provide the same string to:

read -r name name1

name="hello", name1="world". What if you have excess words in the line but only 2 variables? Say your string is now "hello big wide world", what happens with:

read -r name name1

name="hello", name1="big wide world". The words in string are assigned to your variables in order and if there are insufficient variables to hold each word in the string, the last variable will contain all remaining words in the string not previously assigned.

You change how word splitting occurs by altering IFS. Take a close look at the answer provided by anubhava for an example. You are free to specify any character you would like the words to be split on. (helpful in say parsing a csv file to set IFS=$',\n' and have the words split on ',' instead of space)

To ensure you read an entire line into a variable, you can provide only a single variable to read and set IFS='$\n' to ensure word splitting only occurs on newline. (Note: providing the change as part of the while loop limits the IFS alteration to the scope of that loop. For example:

while IFS='$\n' read -r line; do
    # do whatever with line
done

Will ensure that each line on stdin will be read into line while preserving normal word-splitting outside the loop. Inside the loop you can then add each line to an array as anubhava shows in his answer. (to preserve all whitespace IFS= is used)

like image 62
David C. Rankin Avatar answered Oct 01 '22 01:10

David C. Rankin


You can do something like this:

# array to hold all lines read
lines=()

# read all lines in lines array
while IFS= read -r line; do
    lines+=( "$line" )
done < file

# read 3 more lines from stdin
for ((i=0; i<3; i++)); do
   read -rp "Enter a line: " line
   lines+=( "$line" )
done
like image 26
anubhava Avatar answered Oct 01 '22 03:10

anubhava