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
  • $0Command to start the current process
  • The $1Current 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 runningsleep 15This instruction.
  • 11686 Read the Hello fileLr -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/bashAt 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 ./helloThis process is 14967, and the instructions running inside are its children.
  • In order to#! /bin/shThe 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,ulimitEcho 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.