Sunday, May 25, 2014

Unix Shell Built-in Commands(1)

1. Command look-up Order:
Special Built-In Command: break, eval, continue, exit export, readonly, set etc.
Shell Functions: function defined by user at the shell
Regular Built-In Command: read cd umask command jobs etc.
External Commands listed in $PATH

2. Define one Shell function:
terminal:
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ test() {  
 > echo Hello world  
 > }  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ test  
 Hello world  

3.Shell function can be re-defined and override
terminal:
We re-define chdir after the first definition, then run chdir, chdir will follow the 2nd definition.
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir() {  
 > echo "$@"  
 > }  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir ..  
 ..  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir ../..  
 ../..  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir ~/Desktop/xxdev  
 /home/aubinxia/Desktop/xxdev  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir() {  
 > echo "$@"  
 > cd "$@"  
 > }  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ chdir ../..  
 ../..  

4. A more complicated shell function
terminal:
In this shell function, we firstly use "cd" to enter the provided path, and PS1 controls the "look" of shell's prompt. "PS1="${x##*/}\$" means,  it will look for the longest pattern "*/" from the beginning of $x. If found, then remove that pattern and return the remaining part of the variable. \$ means treat $ literally.
So the entire statement means, remove front part of $x until the /, only leave the last path name, add a $. This is the prompt we want!
 aubinxia@aubinxia-fastdev:~$ chdir() {  
 > echo "$@"  
 > cd "$@"  
 > x=$(pwd)  
 > PS1="${x##*/}\$"  
 > }  
 aubinxia$chdir ./Desktop  
 ./Desktop  
 Desktop$chdir ./xxdev  
 ./xxdev  
 xxdev$  

5. Override regular built-in function
Since the command look-up order is: special built-in command, shell function, regular built-in command, and external commands. We can define a shell function with the same name from one regular built-in command, then we can override that regular built-in command!

terminal:
 aubinxia@aubinxia-fastdev:~$ cd() { echo "$@"; cd "$@"; x=$(pwd); PS1="${x##*/}\$ "; }  
 aubinxia@aubinxia-fastdev:~$ cd Desktop  

In above example, we override the regular built-in function "cd". And the last command "cd Desktop" will call our own cd function. But the problem is: inside the definition of cd function, we call "cd "$@"", which makes it call own own cd function recursively! So after calling the last command, we are entering one infinite loop.

6. Use "command" to call built-in function
"command" forces the shell to look up the command with the order : special  built-in command, regular built-in command and external function in the list of $PATH

The correct override cd function:
terminal:
The only difference here is using "command" to prefix "cd "$@"". Then shell will look up the "cd" function from the built-in command list.
 aubinxia@aubinxia-fastdev:~$ cd() { echo "$@"; command cd "$@"; x=$(pwd); PS1="${x##*/}\$ "; }  
 aubinxia@aubinxia-fastdev:~$ cd Desktop  
 Desktop  
 Desktop$ cd xxdev  
 xxdev  
 xxdev$   

7. "command" with -p
./script_1:
 #! /bin/bash  
 echo "Hello world! script_1 is running!"  

terminal:
As mentioned above, command will use look-up order: special built-in command, regular built-in command, and external commands listed inside the $PATH. We can use -p to provide an override $PATH value, then command will tell shell to look up command at the provided $PATH place.

1) First command, it recognize script_1 because we provided the path
2) Second command, it doesn't recognize script_1 because we don't provide the path
3) Third command could recognize script_1, because we use -p to override the $PATH, and let command to search command from here.

 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ command ./script_1  
 Hello world! script_1 is running!  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ command script_1  
 script_1: command not found  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$ command -p . script_1  
 Hello world! script_1 is running!  
 aubinxia@aubinxia-fastdev:~/Desktop/xxdev$   

8. Special built-in command feature:
./script_1:
 #! /bin/bash  
 var="Hello world!"  
 echo $var  

 #Although we change the variable value at following lines  
 #But right after the command running, including special built-in  
 #command(shift) and regular built-in command(echo), $var is still  
 #not changed. This indicates that variable assignment along with   
 #command is not working!  
 var=2 shift  
 var=0 echo $var #still output "Hello world!"  

 echo $var #output "Hello world!"  

No comments:

Post a Comment