This is the sixth day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021.
It’s common to find typed shell commands that are not found in history. Do you know why?
We also often feel that the environment variable set does not take effect, and it is fine again after operation. Have you carefully thought about the principle?
This paper will analyze the principle in depth.
This is the second part of the shell series. The first part is SSH, shell and terminal (1). If you are interested, you can read it.
Bash program parameters and return values
A program is a black box with inputs and outputs, and a shell program has some custom variables
$$
Current Process ID$0
Command to start the current processThe $1
Current input parameter
# ps $$
PID TTY STAT TIME COMMAND
8898 pts/1 Ss 0:00 -bash
# echo $$
8898
Copy the code
- Exit command: status Returns 0 for success and 1 for failure
- A process has a configuration file, which is usually read during initialization
- Bash has configuration files
/root/.bash_profile
Etc. - History also has configuration files
- Various other programs have configuration files
Environment variables and shells
Both systems and procedures
Environment variables are variable information for use by the operating system or application.
# echo $HISTFILE
/root/.bash_history
Copy the code
- You can set overall environment variables
- Processes can also set their own environment variables individually
Isolation of environment variables
- Environment variables set using the shell’s built-in export are currently valid for bash. The export command can add, modify, or delete environment variables
- The environment variables set by export are isolated at bash, with A only taking effect at BASH1 and B only at BASh2.
This is why we often feel that setting environment variables doesn’t work.
Sharing of environment variables
Export needs to be written to the bash configuration file to take effect globally:
- Other bash concurrently executes source to see other bash environment variables.
- The new bash starts with the commands in the configuration file.
The diagram below:
- The alias setting alias works the same way, because it is also the default configuration file for bash.
#echo "alias ll=\"ls -l\"" >>.bash_profile
#. .bash_profile
Copy the code
- The source and. It is the same, it is re-read from the configuration file and execute the commands in the configuration file.
- The commands mentioned here are all built-in commands of the shell, and they run in the shell process (they don’t start a new process).
Environment variables are inheritable
-
Because the child process inherits the parent’s data space, the child process can inherit the parent’s environment variables at startup
-
On bash terminals, the environment variables set are visible to all programs executed by the terminal, since they are child processes of Bash.
Start a new bash as follows and you can still read $AAA.
# export AAA=a
# echo $AAA
a
# bash
# echo $AAA
a
Copy the code
- The same goes for daemons.
The SHELL HISTORY HISTORY
It’s common to find typed shell commands that are not found in history. Do you know why?
History (history [n]) command
Basic usage and associated environment variables
- Arguments to n list only the last n lines.
- If the shell variable HISTTIMEFORMAT is set, the time is displayed
As shown below:
# echo $HISTTIMEFORMAT
%F %T
# history 2
2989 2021-11-14 08:45:35 whereis java
2990 2021-11-14 08:45:48 ll -a /usr/bin/java
#echo $HISTFILE
/root/.bash_history
# echo $HISTSIZE
3000
# history |wc -l
3000
Copy the code
- HISTFILE is a record file of history history files.
- HISTSIZE is the maximum number of rows for HISTFILE
- There are also some variables that are not commonly used
Options and Functions
Principle of push and pull
History has several important options that provide the following functionality:
- -a Appends a “new” history line to the history file starting with the current bash.
- -n Reads the history line that has not been read from the history file into the current history list. These are the lines that have been attached to the history file since the current Bash session began.
- -a Performs logic and interactive input. The history command is not repeated and common commands can also be specified to be ignored
- -n Reads the history line that has not been read from the history file into the current history list
We often find that the input shell command cannot be found in history, because we do not know that the history record of shell is saved in memory and only saved to the file when executing commands or exiting normally. And there are too many exceptions out there.
Abnormal exit
The bash process exits with a history of its execution. Many exceptions cause the shell to break, such as:
- Power outages
- Broken network
- The terminal was forcibly shut down
It is also possible that bash has the behavior of keeping a history on a regular basis, but if there are important commands that need to be saved in time, don’t take any chances.
So that explains why history can’t find commands that were ever executed.
The other options
There are a few other options, but it’s basically not important, know or don’t know.
- History -c deletes all entries to clear the history list and returns everything to zero.
- -d offset: deletes the historical record at the offset position.
- -r reads the contents of the history file and uses it as the current history
- -w Writes the current history to the history file to overwrite the content of the history file
shortcuts
- CTRL+R: Searches for the latest history command
#(reverse-i-search)\`do\`:
- Up and down arrows: Find one or more of the previous commands that were just executed.
Does the shell script have a history?
A shell script
As mentioned above, a shell script is a script file that is run through bash. As mentioned earlier, a bash program is a black box with inputs and outputs: $$Current bash process ID, $0 current shell instruction, $1 current input parameter…
But does the shell script have a history?
/bin/bash(PID=9923)
Small experiment 1
- The hello script file does not specify a shell. Here is all:
echo "Hello World !"
sleep 15
echo "done"
Copy the code
Run chmod a+x hello &&./hello to start a new bash, where these commands are executed in sequence:
# ps -ef |grep 9923
root 9923 9920 0 16:59 pts/1 00:00:00 -bash
root 11686 9923 0 17:04 pts/1 00:00:00 -bash
# ps -ef |grep 11686
root 11686 9923 0 17:04 pts/1 00:00:00 -bash
root 11687 11686 0 17:04 pts/1 00:00:00 sleep 15
Copy the code
As you can see,
- 11686 is the newly started bash process and is running
sleep 15
This instruction. - 11686 Read the Hello file
Lr -x------ 1 root root 64 11月 15 21:43 254 -> /root/hello
- When basH2 command is executed, 11686 exits
- After exiting, execution records are not saved to the history file
Small experiment 2
- In order to
#! /bin/bash
At the beginning
#! /bin/bashecho "Hello World !" .Copy the code
Effect:
# ps -ef |grep 9923
root 9923 9920 0 16:59 pts/1 00:00:00 -bash
root 14967 9923 0 17:15 pts/1 00:00:00 /bin/bash ./hello
# ps -ef |grep 14967
root 14967 9923 0 17:15 pts/1 00:00:00 /bin/bash ./hello
root 14968 14967 0 17:15 pts/1 00:00:00 sleep 15
Copy the code
It can be seen that
- use
/bin/bash ./hello
This process is 14967, and the instructions running inside are its children. - In order to
#! /bin/sh
The script at the beginning is the same as above, except that the process running is sh-/bin/sh ./hello
- You can also see the PID of the sleep processIt’s only 1 larger than the shell it’s running onEcho does not create a new process because the process ID is monotonically increasing.
- The Shell requests the system to create a new process when executing an external command or subscript
- Shell internal commands do not create new processes
- The built-in commands are numerous, including
alias, bg,cd, echo, exit, export, fg, help, history, jobs, kill, pwd, read, set, source,type,ulimit
Echo is also a built-in command
# type echoEcho is embedded in the shellCopy the code
Small experiment 3
Type bash inside bash
# bash
# whoami
root
# exit
exit
# history -n
Copy the code
- The child process bash performs whoami
- The child process bash Exit
- The parent process executes history -n
- The parent bash process can scroll up and down to the whoami history command
But previous shell scripts have no history. Why is that?
You can guess that the shell is not interactive, but a read file, so it is not recorded in a history file.
- Shell bash is interactive with the -i option, or with no file reading, or with the -c option (reading commands from string), otherwise it is not.
- The history feature is designed for interactive use; non-interactive commands do not record the history file.
So back to the question, does a shell script have a history?
The answer is no.
Next
The next article on Shell systems will cover exec and the two command launch modes in Docker: Exec and Shell.
If this article is helpful or inspiring to you, please like it or follow :), your support is the biggest motivation for me to keep writing.