Linux (BASH) command search mechanism

Source: Internet
Author: User
Tags builtin

From: http://www.mike.org.cn/articles/linux-linux-bash-command-search-mechanism/

This document assumes that the environment is GNU/Linux and the shell is Bash;

Note: In addition, we discuss the premise that when you type a command, the path of the command is not specified, for example, the command we typed is in the form of commandname rather than/path/commandname or. /path/commandname. once the relative or absolute path of a command (or script or binary file) is specified, no search mechanism is available.

The content of this article is: Normally, how does Shell find this command when we type commands such as ls at a Linux terminal prompt? What types of commands does Shell have? How are these commands loaded?

I. Classification of Linux commands:

Including: alias, keyword, function, built-in, and $ path

Ii. Linux Command search sequence:

When we type a command, shell searches in the order of alias-> keyword-> function,-> built-in-> $ path, based on the "first come, first served" principle, that is, if a command named mycmd exists in both alias and function, it will certainly use the alias mycmd command (of course, this is not absolute, special cases will be mentioned below ).

Iii. Related

Set +-h, hash, type, command, enable, builtin

1) Hash command:

First, let's take a look at the Hash command (it has something to do with the "not absolute" I mentioned above !), The Hash command is used to record the cache table of the command path you have typed in the Current Shell environment. It is mainly used to speed up command search. The following is an example:

For example, I typed ls, find, PWD, ls, Echo "Hello, world", mail, and if COMMANDS IN SHELL (note that ls is executed twice ), the result of history is as follows:

1 ls
2 find
3 pwd
4 Ls
5 echo "Hello, world"
6 mail
7 if

Now, when I run the Hash command, the result is:

[Ancharn @ fc8 ~] $ Hash
Hits command
1/bin/mail
2/bin/ls
1/usr/bin/find

I don't know what you found? The left column of the hash table indicates that the command has been used several times in the Current Shell environment, and the right column indicates the command path. however, we found that the hash cache lacks the IF, PWD, and echo3 commands. Why? Here we need to draw an important conclusion: (1) hash won't record function, built-in command (actually including alias). Why? The answer is that they do not have a path, that is, they do not exist in a directory. They are loaded with Shell and then stored in memory, so is it necessary to cache such a command to improve search efficiency ?!

But some people will say, isn't ls recorded by hash? Yes, your observations are very meticulous. Normally, LS is an alias in Bash. So here we will come to the following conclusion: (2) if alias defines an alias containing a path, it will not be recorded in the hash. Only alias with no specified path will be recorded in the hash. example:

This is the definition of the LS alias in my current shell (BASH) environment.

[Ancharn @ fc8 //] $ alias ls
Alias ls = 'LS-color = auto'

(Note: "ls-color = auto" does not specify a path such as/bin/LS)

So, as you can see, I typed Two Ls commands (alias of LS-color = auto) above, so we can see the records in the hash; the following is an example of the write command:

[Ancharn @ fc8 //] $ alias write
-Bash: alias: Write: not found

[Ancharn @ fc8 //] $ write
Usage: write user [tty]

[Ancharn @ fc8 //] $ hash
Hits command
1/usr/bin/Write
1/bin/mail
2/bin/ls
1/usr/bin/find

The write command does not have alias, that is, when the write command is executed, the/usr/bin/Write binary file in the PATH variable is actually found for execution, at this time, the hash records the write path and is referenced once. Then I define the write alias as write, but specify the specific path as/usr/bin/write:

[Ancharn @ fc8 //] $ alias write = '/usr/bin/write'
[Ancharn @ fc8 //] $ alias write
Alias write = '/usr/bin/write'
[Ancharn @ fc8 //] $ write
Usage: write user [tty]
[Ancharn @ fc8 //] $ hash
Hits command
1/usr/bin/Write
1/bin/mail
2/bin/ls
1/usr/bin/find

Please see, the number of hits of write in the hash table is still 1; note that when we define the write alias (specify the path), the path will not be searched, why? It's easy, because the specific path of the write alias has been specified!

Then unalias drops write to redefine the write alias:

[Ancharn @ fc8 //] $ unalias write
[Ancharn @ fc8 //] $ alias write
-Bash: alias: Write: not found

[Ancharn @ fc8 //] $ alias write = 'write'
[Ancharn @ fc8 //] $ alias write
Alias write = 'write'

[Ancharn @ fc8 //] $ write
Usage: write user [tty]

[Ancharn @ fc8 //] $ hash
Hits command
2/usr/bin/Write
1/bin/mail
2/bin/ls
1/usr/bin/find

This time, we didn't specify the path in the write alias. When we define the write alias and execute the write operation, the hits will be added to the hash table. note that after we define the write alias (do not specify the path, please compare it with the above example), the path will be searched, therefore, hits of hash is added. please remember that if alias defines an alias containing a path, it will not be recorded in the hash. Only alias with no specified path will be recorded in the hash.

In addition, because hash is a built-in command, help hash is used to view help. Hash-R is commonly used to clear the hash table, and hash-D name is used to delete a command. For example:

[Ancharn @ fc8 //] $ hash
Hits command
3/usr/bin/Write
1/bin/mail
2/bin/ls
1/usr/bin/find

Delete specific:
[Ancharn @ fc8 //] $ hash-d ls
[Ancharn @ fc8 //] $ hash
Hits command
3/usr/bin/Write
1/bin/mail
1/usr/bin/find

Clear hash:
[Ancharn @ fc8 //] $ hash-R
[Ancharn @ fc8 //] $ hash
Hash: hash table empty

2) Set +-h:

You should be familiar with the set command. Here we mainly talk about the function of set +-H: help set can see "-h remember the location of commands as they are looked up. "Chinese means the path of the memory command for query. after we type set + H, run hash:

[Ancharn @ fc8 //] $ set + H
[Ancharn @ fc8 //] $ hash
-Bash: Hash: hashing disabled

That is to say, "set + H" is used to disable hash and "Set-h" is used to enable hash.

3) type:

This command is used to list the types of commands. For example:

[Ancharn @ fc8 //] $ type-A pwd
PWD is a shell builtin
PWD is/bin/pwd
PWD belongs to the built-in and PATH variables.

[Ancharn @ fc8 //] $ type pwd
PWD is a shell builtin
Directly Using type commandname can tell you which type of command will be executed during running.

4) command:

The purpose of this command is: If you have a command such as GCC, which is both a function and a command in the PATH variable, If you directly execute GCC, in order, the command in the function instead of the gcc path variable is executed, while the command GCC skips the function selection.

[Ancharn @ fc8 //] $ function GCC {echo "just a test for GCC ";}

[Ancharn @ fc8 //] $ gcc
Just a test for GCC

[Ancharn @ fc8 //] $ command gcc
GCC: no input files

5) enable:

If you run the enable command directly, all built-in commands of the current shell will be listed. Enable-N commandname will disable the built-in command under the current shell:

[Ancharn @ fc8 ~] $ Type-A pwd
PWD is a shell builtin
PWD is/bin/pwd

[Ancharn @ fc8 ~] $ Enable-N pwd
[Ancharn @ fc8 ~] $ Type-A pwd
PWD is/bin/pwd

[Ancharn @ fc8 ~] $ Enable pwd
[Ancharn @ fc8 ~] $ Type-A pwd
PWD is a shell builtin
PWD is/bin/pwd

6) builtin

Run a built-in command. For example:

[Ancharn @ fc8 ~] $ CD/var
[Ancharn @ fc8 var] $ function PWD {echo "just a test for PWD ";}
[Ancharn @ fc8 var] $ type-A pwd
PWD is a function
PWD ()

{
Echo "just a test for PWD"
}
PWD is a shell builtin
PWD is/bin/pwd

(Note: Pwd is both a function, a built-in command, and a path variable)

[Ancharn @ fc8 var] $ pwd
Just a test for PWD
[Ancharn @ fc8 var] $ builtin PWD // (Note: We will directly execute the built-in command PWD)
/Var

Summary: We all know that the order of shell search commands is alias-> keyword-> function,-> built-in-> $ path, so there are two points to note: (1) hash won't record function, built-in command (actually including alias), (2) if alias defines an alias containing a path, it will not be recorded in the hash. Only alias with no specified path will be recorded in the hash. in addition, (3) do not forget that the premise we discuss is a) Limited by the specific shell type B) and only valid in the current shell environment. remember !!!

Here, let's take a look at the following question:

See the following implementation:

[Ancharn @ fc8 var] $ function GCC {echo "just a test for GCC ";}
[Ancharn @ fc8 var] $ alias GCC = 'gcc'

[Ancharn @ fc8 var] $ gcc
Just a test for GCC

[Ancharn @ fc8 var] $/usr/bin/GCC
GCC: no input files

[Ancharn @ fc8 var] $ alias GCC = '/usr/bin/GCC'
[Ancharn @ fc8 var] $ gcc
GCC: no input files

[Ancharn @ fc8 var] $

After the GCC funtion is defined, when the alias of GCC is defined twice and the specific/usr/bin/GCC path is not specified, the execution of the GCC command is different? According to the order of alias-> keyword-> function,-> built-in-> $ path, the alias GCC should be executed ?! Think about it!
Of course, don't worry. I will give you the answer later. But please think about it!

4. Command example:

* Alias (alias ):
The alias command is usually set in the file ~ /. Bashrc and/etc/bashrc ,~ /. Bashrc is usually used in your own environment, while/etc/bashrc is used for global definition (that is, effective for all users, of course, only effective for User Shell is Bash ). the relationship between the two files and how to load them are described later.

* Shell keyword (shell keyword ):
Such as if, while, until, case, for commands.

* Function ):

Example:

Define a function named PWD. Its function is to simply display the sentence "My function PWD ".
Function PWD {echo "My function PWD ";}
After the definition, you can use set or Type-a pwd to view it. To cancel the definition, use unset PWD.

* Shell built-in command (shell built-in command ):
The enable command can be used to view all built-in commands in the Current Shell environment, or all the built-in commands are listed in the upper part of the manpage that can be viewed by man Cd (any built-in command.

* PATH variable
This variable is defined in the file/etc/profile,/etc/profile. d/*. Sh (POSIX ),~ /. Bash_profile (BASH.

The loading sequence is: first/etc/profile (invoke/etc/profile. d/*. Sh), then ~ /. Bash_profile, and then ~ /. Bash_profile call execution ~ /. Bashrc, and then ~ /. Bashrc to call and execute ~ /. Bashrc ,~ /. Bashrc then calls the execution file/etc/bashrc.

1) to view the specific loading sequence, you can add two sentences to the header and tail of the four files, for example:

[Ancharn @ fc8 ~] $ Cat ~ /. Bashrc
Echo "Start ~ /. Bashrc"
If [-F/etc/bashrc]; then
./Etc/bashrc
Fi
Alias LL = 'LS-l'
Alias CP = 'cp-I'
Alias mv = 'mv-I'
Alias Rm = 'rm-I'
......

Echo "End ~ /. Bashrc"
Add other files, so that you will see the following display when logging on to the system with a user, such:
Start of/etc/profile
End of/etc/profile
Start ~ /. Bash_profile
Start ~ /. Bashrc
Start of/etc/bashrc
End of/etc/bashrc
End ~ /. Bashrc
End ~ /. Bash_profile

From the above, you can clearly see the loading sequence of each file and the invocation relationship between each other (check start and end ).

2) Relationship between PATH variables and hash
Here, let's look at an example:

[Ancharn @ fc8 ~] $ Echo $ path
/Usr/Kerberos/bin:/usr/local/bin:/usr/bin:/home/ancharn/bin

First, write a script named test. Sh in the/home/ancharn/bin directory. The content is as follows:
[Ancharn @ fc8 bin] $ CAT/home/ancharn/bin/test. Sh

#! /Bin/sh
# Just test for path and hash
Echo "this is my 1st shell script in/home/ancharn/bin directory ."

# End

[Ancharn @ fc8 bin] $
Run the test. Sh script as follows:
[Ancharn @ fc8/] $ echo $ path
/Usr/Kerberos/bin:/usr/local/bin:/usr/bin:/home/ancharn/bin
[Ancharn @ fc8/] $ test. Sh
This is my 1st shell script in/home/ancharn/bin directory.
[Ancharn @ fc8/] $ hash
Hits command
1/home/ancharn/bin/test. Sh
Create a file with the same name as test. Sh in the/usr/bin directory. The content is as follows:

[Ancharn @ fc8/] $ CAT/usr/bin/test. Sh
#! /Bin/sh
# Just test for path and hash
Echo "this is my 2nd shell script in/usr/bin directory ."

# End
Continue to execute the test. Sh script:

[Ancharn @ fc8/] $ test. Sh
This is my 1st shell script in/home/ancharn/bin directory.
[Ancharn @ fc8/] $ hash
Hits command
2/home/ancharn/bin/test. Sh

What is it about?

If the path is/usr/Kerberos/bin:/usr/local/bin:/usr/bin:/home/ancharn/bin, first find/usr/bin and then find/home/ancharn/bin. Note that the command is not recorded in the hash table, so we can see/usr/bin/test. the sh script is not executed because the test. before SH, shell checked the cache in the hash table, and then continued to execute/home/ancharn/bin/test. sh script, so we can see that the number of hits is increased once, and/usr/bin/test. sh will not be executed.

Now, clear the hash and re-execute the test. Sh script:

[Ancharn @ fc8/] $ hash-R
[Ancharn @ fc8/] $ hash
Hash: hash table empty
[Ancharn @ fc8/] $ test. Sh
This is my 2nd shell script in/usr/bin directory.
[Ancharn @ fc8/] $ hash
Hits command
1/usr/bin/test. Sh

Now it is normal. So pay attention to the relationship between path and hash.

Note: The difference between the Su, Su-, bash-login, and bash-NORC commands is whether login-shell is executed, run echo $ path again to see what's different.

Well, the core of answering the above questions is that if alias is defined as Alias GCC = 'gcc ', alias-> keyword-> function, -> the order of built-in-> $ PATH has not changed. However, if alias GCC = 'gcc 'and alias without a specified path are found, find the 'gcc 'specified later. How can this problem be found? Of course, the next step is the keyword-> function .... In this order. if alias GCC = '/usr/bin/GCC' is used to define a specific path, after alias is executed, it finds the specific file and skips all subsequent searches (I .e., keyword-> function,-> built-in-> $ PATH ). please note.

Finally, we can divide the test into two types for verification, because a command cannot belong to both Keyword and built-in, so you can:

1) Select a keyword such as while, define a while alias and function, and write a shell script named while stored in a path of the PATH variable;

2) Select a built-in command such as Pwd for verification.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.