Saturday, May 24, 2014

Unix Shell Evaluation Order: eval

1. Unix Shell evaluation order
 #! /bin/bash  

 num=10  

 if [ $num -ge 2 ]  
 # 1. The shell will separate the statement into different tokens by  
 #  using the fixed set of metacharacters(tab, space etc.)  
 # 2. Check the first word "if", whether it is keyword or not, if yes,  
 #  Then it will setup the internal configuration for "compound command"  
 #  and then ready to read next command  

 then  
 #it is exactly same as above, "then" is shell keyword, the shell will setup  
 #internally for "compound command"  

   f=Desktop  
   y="hello world"  
   echo ~/${f} $y $(echo my world) $((3+2))   
 #1. Similar, separate the statement into different tokens by using the  
 #  fixed set of metacharacters.   
 #2. Check the first word "echo", it is not keyword in this case, so proceed  
 #  to next step  
 #3. Check first word whether it is aliases if yes, substitute it with the   
 #  alias then go back to step 1(need to re-check if it is keyword)  
 #4. Scan all words for tilde expansion, in this case, ~ will be substituted,  
 #  so, the statement will be like:  
 #  echo /home/aubinxia/${f} $y $(echo my world) $((3+2))  
 #5. Scan all words for variable substitution. In this case, ${f} will be substituted  
 #  with Desktop, $y will be replaced with "hello world", and right now the  
 #  statement is like:  
 #  echo /home/aubinxia/Desktop hello world $(echo my world) $((3+2))  
 #6. Scan all words for command substitution. In this case, $(echo my world) will be  
 #  run and substituted with "my word". Note at this step, it will recursively go  
 #  through all steps from step 1. Right now the statement is like:  
 #  echo /home/aubinxia/Desktop hello world my world $((3+2))  
 #7. Scan all words for arithmetic substitution. In this case, $((3+2)) will be replaced  
 #  with 5. And right now the statement is like:  
 #  echo /home/aubinxia/Desktop hello world my world 5  
 #8. Go through all words again and use IFS as separator to get all words again:  
 #  Before this step, statement has 5 words:  
 #  1) echo  
 #  2) /home/aubinxia/Desktop  
 #  3) hello world(because it is from original word: $y)  
 #  4) my world(because it is from original word: $(echo my world))  
 #  5) 5  
 #  
 #  after this step, statement has 7 words:  
 #  1) echo 2) /home/aubinxia/Desktop 3) hello 4) world 5) my 6) world 7) 5  
 #9. Scan all words for wildcard expansion.  
 #10. Run the final command, and start to look up echo in shell.  

 fi  

2. eval statement:
eval statement force shell to re-go-through all steps needed in evaluation again.
script:
 #! /bin/bash  

 comm="ls -lrt | sort"  
 $comm  
 #output:  
 #ls: cannot access |: No such file or directory  
 #ls: cannot access sort: No such file or directory  
 #  
 #The reason:  
 #when running $comm, it already comes to the evaluation step:  
 #variable substitution. The remaining steps are just for  
 #word separation and run the command.  
 #  
 #So "-lrt | sort" are just taken as the parameter of ls!  
 #  
 #If we want to to separate ls and sort to different commands  
 #we have to go through the step 1 in evaluation process.  
 #Here is the better way:  
 #eval will let $comm go through the evaluation process again  

 eval $comm  
 #output:  
 #-rw-rw-r-- 1 aubinxia aubinxia  0 May 20 22:33 backup  
 #-rw-rw-r-- 1 aubinxia aubinxia  12 May 24 11:16 script?  
 #-rw-rw-r-- 1 aubinxia aubinxia  12 May 24 11:16 script2  
 #-rw-rw-r-- 1 aubinxia aubinxia  34 May 24 16:02 out  
 #-rw-rw-r-- 1 aubinxia aubinxia  35 May 24 10:34 text  
 #-rw-rw-r-- 1 aubinxia aubinxia  53 May 18 18:55 text~  
 #-rw-rw-r-- 1 aubinxia aubinxia 8453 May 17 11:52 backup~  
 #-rwxrwxr-x 1 aubinxia aubinxia 539 May 24 16:52 script_1  
 #total 36  

3. subshell & code block
subshell will start the new process, which is not related with current process
./script_1:
inside the subshell, we go to the another folder, and pwd is already changed.
But right leaving the subshell, we come back to the current  process, pwd doesn't change, since the change in another process will not affect the current process.
 #! /bin/bash  
 (cd ../..;pwd)  
 echo =====  
 pwd  

terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_1  
 /home/aubinxia  
 =====  
 /home/aubinxia/Desktop/xxdev  
====================================
./script_1:
code block using braces have to use format like following code. It can coexist with other codes in the same line like sub shell.
Two occurances of pwd show the same path, meaning that code block share the same state with parent process. For the shell, it doesn't start a new process when entering a a code block.
 #! /bin/bash  
 {   
   cd ../..  
   pwd   
 }  
 echo =====  
 pwd  

terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_1  
 /home/aubinxia  
 =====  
 /home/aubinxia  
====================================
./script_1:
Following example indicate that even if we use the subshell to start a new process, it still "inherits" all information from the parent process and pwd show the same path as the parent's one.
 #! /bin/bash  
 cd ../..  
 pwd  
 ( pwd )  

terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ ./script_1  
 /home/aubinxia  
 /home/aubinxia  

No comments:

Post a Comment