Sunday, May 18, 2014

Unix Shell Readling Lines: read

1. Basic Usage
./script_2
 #! /bin/bash  

 printf "Please input two strings:"  
 read var1 var2  
 echo $var1, $var2  

terminal:
There are 2 ways to put in string from standard input:
1) "Hello world", the shell will use variable IFS as the separator to read in different strings into different varaibles
2) "Hello \
world", the backslash and new line operator make shell think, it should go to the next line to read in next string.
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 Please input two strings:Hello world  
 Hello, world  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 Please input two strings:Hello \  
 world  
 Hello, world  
=====================================
./script_2:
 #! /bin/bash  

 printf "Please input two strings:"  
 read -r var1 var2  
 echo $var1, $var2  

terminal:
The only difference of above script is using "-r" option for read command. It make shell think: backslash is not the indicator to skip and read variable from the next line, it will read it into the next variable. -r means "raw read"
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 Please input two strings:Hello \  
 Hello, \  

2. Change Default Separator
./script_2:
 #! /bin/bash  

 IFS=':'  
 printf "Please input 3 strings separated by colon:"  
 read var1 var2 var3  
 echo $var1:$var2:$var3  

terminal:
We changed the default separator to ":". And the first command although use backslash in the end, since it only recognize ":" as the default separator, so the first variable is still "34"!
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 Please input 3 strings separated by colon:3\  
 4:5:6  
 34:5:6  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 Please input 3 strings separated by colon:4:5:6  
 4:5:6  

3. read with inconsistent number of variables
text:
 Hello, New York  

script_2:
 #! /bin/bash  

 IFS=' '  
 read var1 var2<./text  
 echo $?  
 echo $var1  
 echo $var2  

 read var1 var2 var3<./text  
 echo $?  
 echo $var1  
 echo $var2  
 echo $var3  

 read var1 var2 var3 var4<./text  
 echo $?  
 echo $var1  
 echo $var2  
 echo $var3  
 echo $var4  

terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 1  
 Hello,  
 New York  
 1  
 Hello,  
 New  
 York  
 1  
 Hello,  
 New  
 York  


Above example demonstrates that what happens if the number of provided arguments at input is different from the number of "read variables" in script.
If there are fewer read variables, all the remaining strings at input will be put into the last variable.
If there are more read variables, then remaining variables will be assigned empty string. That's why the last read command(4 variables), when printing out echo4, in terminal it is just one empty line.

Note: in text file, there is no newline operator in the end. So read return status 1,
if the line of input text end up with newline operator, read will return status 0, since it means there is more thing waiting to be read. Following example can demonstrate this:

text  file is almost same as above, the only difference is: we add a new line operator at the end of string.

script_2:
 #! /bin/bash  

 IFS=' '  
 read var1<./text  
 echo $?  
 echo $var1  

terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 0  
 Hello, New York  

3. read in pipeline and loop
./script_2
 #! /bin/bash  

 var1=Hello  
 cat ./text | read var1  
 echo $?  
 echo $var1  
 echo "================================"  
 cat ./text | \  
 while read var1  
 do  
   echo $?  
   echo $var1  
 done 
 echo $var1 

terminal:
following result is very surprising. The reason is: when read in the pipeline, the shell normally starts a separate process to handle it. Separate process means, it has its own variable space, which is not related with parent script's at all!.

So the reason the first "read" command doesn't change the value of var1 is, read command change the var1 of its own process's variable space.

And the reason the 2nd "read" command does change the value fo var1 "inside the while scope" is: read command and while loop are in the same process! And they share the same variable space. So leaving the "while loop space", and try to print var1 again, we figured that it is still "Hello", since we return back to the script's process space, and it never change at all.
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_2  
 0  
 Hello  
 ================================  
 0  
 Hello, New York  
 Hello

No comments:

Post a Comment