-->

Understanding Shell Built-In Commands

While learning about the GNU bash shell, you likely have heard the term built-in command. It is important to understand both shell built-in and non-built-in (external) commands. Built-in commands and non-built-in commands operate very differently.

Looking at external commands

An external command, sometimes called a filesystem command, is a program that exists outside of the bash shell. They are not built into the shell program. An external command program is typically located in /bin, /usr/bin, /sbin, or /usr/sbin.

The ps command is an external command. You can find its filename by using both the which and the type commands:

$ which ps
/bin/ps
$$
type -a ps
ps is /bin/ps
$$
ls -l /bin/ps
-rwxr-xr-x 1 root root 93232 Jan 6 18:32 /bin/ps
$

Whenever an external command is executed, a child process is created. This action is termed forking. Conveniently, the external command ps displays its current parent as well as its own forked child processes:

$ ps -f
UID        PID    PPID  C  STIME   TTY         TIME   CMD
christi+   2743   2742  0  17:09   pts/9   00:00:00   -bash
christi+   2801   2743  0  17:16   pts/9   00:00:00   ps -f
$

Because it is an external command, when the ps command executes, a child process is created. In this case, the ps command’s PID is 2801 and the parent PID is 2743. The bash shell process, which is the parent, has a PID of 2743. The picture below is illustrates the forking that occurs when an external command is executed.

External command forking
External command forking


Whenever a process must fork, it takes time and effort to set up the new child process’s environment. Thus, external commands can be a little expensive.

Note
If you fork a child process or create a subshell, you can still communicate with it via signaling, which is extremely helpful in both the command line and in writing shell scripts. Signaling allows process communication via signals. 

When using a built-in command, no forking is required. Therefore, built-in commands are less expensive.

Looking at built-in commands

Built-in commands are different in that they do not need a child process to execute. They were compiled into the shell and thus are part of the shell’s toolkit. No external program file exists to run them.

Both the cd and exit commands are built into the bash shell. You can tell a command is built-in by using the type command:

$ type cd
cd is a shell builtin
$$
type exit
exit is a shell builtin
$

Because they do not need to fork a child process to execute or open a program file, built-in commands are faster and more efficient. A list of GNU bash shell built-in commands is provided in Appendix A.

Be aware that some commands have multiple flavors. For example, both echo and pwd have a built-in command flavor as well as an external command flavor. These flavors are slightly different. To see multiple flavors for commands, use the -a option on the type command:

$ type -a echo
echo is a shell builtin
echo is /bin/echo
$$
which echo
/bin/echo
$$
type -a pwd
pwd is a shell builtin
pwd is /bin/pwd
$$
which pwd
/bin/pwd
$

Using the type -a command shows both types for each of the two commands. Note that the which command shows only the external command file.

Tip
To use the external command for a command that has multiple flavors, directly reference the file. For example, to use the pwd external command, type /bin/pwd.

Using the history command

A useful built-in command is the history command. The bash shell keeps track of the commands you have used. You can recall these commands and even reuse them.

To see a recently used commands list, just type the history command with no options:

$ history

  1. ps -f
  2. pwd
  3. ls
  4. coproc ( sleep 10; sleep 2 )
  5. jobs
  6. ps —forest
  7. ls
  8. ps -f
  9. pwd
  10. ls -l /bin/ps
  11. history
  12. cd /etc
  13. pwd
  14. ls
  15. cd
  16. type pwd
  17. which pwd
  18. type echo
  19. which echo
  20. type -a pwd
  21. type -a echo
  22. pwd
  23. history


In this example, only the last 23 commands are shown. Typically, the last 1,000 commands are kept in history. That is lots of commands!
Tip
You can set the number of commands to keep in the bash history. To do so, you need to modify an environment variable called HISTSIZE.
You can recall and reuse the last command in your history list. This can save time and typing. To recall and reuse your last command, type !! and press the Enter key:

$ ps —forest
PID TTY TIME CMD
2089 pts/0 00:00:00 bash
2744 pts/0 00:00:00 \_ ps
$$
!!
ps —forest
PID TTY TIME CMD
2089 pts/0 00:00:00 bash
2745 pts/0 00:00:00 \_ ps
$

When !! was entered, the bash shell first displayed the command it was recalling from the shell’s history. After the command was displayed, it was executed.

Command history is kept in the hidden .bash_history file, which is located in the user’s home directory. Be careful here. The bash command history is stored in memory and then written out into the history file when the shell is exited:

$ history
[…]
25 ps —forest
26 history
27 ps —forest
28 history
$$
cat .bash_history
pwd
ls
history
exit
$

Notice when the history command is run, 28 commands are listed. In the example, the listing is snipped for brevity. However, when the .bash_history file is displayed, only four commands are listed, and they don’t match the history command’s list.

You can force the command history to be written to the .bash_history file before leaving a shell session. In order to force this write, use the -a option on the history command:

$ history -a
$$
history
[…]
25 ps —forest
26 history

27 ps —forest
28 history
29 ls -a
30 cat .bash_history
31 history -a
32 history
$$
cat .bash_history
[…]
ps —forest
history
ps —forest
history
ls -a
cat .bash_history
history -a

This time both listings need to be snipped because they are so long. Notice that contents from both the history command and the .bash_history file match, except for the very last command listed for the history command, because it came after the history -a command was issued.

Note
If you have multiple terminal sessions open, you can still append the .bash_history in each open session using the history -a command. However, the histories are not automatically updated for your other open terminal sessions. This is because the .bash_history file is read only when a terminal session is first started. To force the .bash_history file to be reread and a terminal session’s history to be updated, use the history -n command.

You can recall any command from the history list. Just enter an exclamation point and the command’s number from the history list:

$ history
[…]
13 pwd
14 ls
15 cd
16 type pwd
17 which pwd
18 type echo
19 which echo
20 type -a pwd
21 type -a echo
[…]
32 history -a
33 history
34 cat .bash_history
35 history
$$
!20
type -a pwd
pwd is a shell builtin
pwd is /bin/pwd
$

Command number 20 was pulled from command history. Notice that similar to executing the last command in history, the bash shell first displays the command it is recalling from the shell’s history. After the command is displayed, it is executed.

Using bash shell command history can be a great timesaver. You can do even more with the built-in history command. Be sure to view the bash manual pages for history, by typing man history.

Using command aliases

The alias command is another shell built-in command. A command alias allows you to create an alias name for common commands (along with their parameters) to help keep your typing to a minimum.

Most likely, your Linux distribution has already set some common command aliases for you. To see a list of the active aliases, use the alias command with the -p parameter:

$ alias -p
[…]
alias egrep=‘egrep —color=auto’
alias fgrep=‘fgrep —color=auto’
alias grep=‘grep —color=auto’
alias l=‘ls -CF’
alias la=‘ls -A’
alias ll=‘ls -alF’
alias ls=‘ls —color=auto’
$

Notice that, on this Ubuntu Linux distribution, an alias is used to override the standard ls command. It automatically provides the color parameter, indicating that the terminal supports color mode listings.

You can create your own aliases using the alias command:

$ alias li=‘ls -li’
$$
li
total 36
529581 drwxr-xr-x. 2 Christine Christine 4096 May 19 18:17 Desktop
529585 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Documents
529582 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Downloads
529586 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Music
529587 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Pictures
529584 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Public
529583 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Templates
532891 -rwxrw-r—. 1 Christine Christine 36 May 30 07:21 test.sh
529588 drwxr-xr-x. 2 Christine Christine 4096 Apr 25 16:59 Videos
$

After you define an alias value, you can use it at any time in your shell, including in shell scripts. Be aware that because command aliases are built-in commands, an alias is valid only for the shell process in which it is defined:

$ alias li=‘ls -li’
$$
bash
$$
li
bash: li: command not found
$$
exit
exit
$

Fortunately, you can make an alias value permanent across subshells. The next chapter covers how to do that, along with environment variables.

Summary

This article discussed the complicated interactive program, the GNU bash shell. It covered understanding the shell process and its relationships, including how subshells are spawned and their relationship to the parent shell. We also explored commands that create child processes and commands that don’t.

The default interactive shell is normally started whenever a user logs in to a terminal. The shell that the system starts depends upon a user ID configuration. Typically, it is /bin/bash. The default system shell, /bin/sh, is used for system shell scripts, such as those needed at startup.

A subshell or child shell can be spawned using the bash command. They are also created when a process list or the coproc command is used. Using subshells at the command line can allow for creative and productive use of the CLI. Subshells can be nested, spawning grandchild shells and great-grandchild shells. Creating a subshell is an expensive process as a new environment for the shell must be created as well.

Finally, the chapter looked at two different types of shell commands: built-in and external commands. External commands create a child process with a new environment, but a built-in command does not. This causes external commands to be more expensive to use.

Because a new environment is not needed, built-in commands are more efficient and not affected by any environment changes.

Shells, subshells, processes, and forked processes are all affected by environment variables. How the variables affect and can be used within these different contexts are explored in the next chapter.

0 Response to "Understanding Shell Built-In Commands"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel