Shell Scripts 1
Shell Overview
Shell is both a powerful command-line interface and a script language interpreter.
The Shell parsers provided by Linux are:
1 | [root@lht ~]# cat /etc/shells |
The relationship between bash and sh:
1 | [root@lht ~]# cd /bin; ll | grep bash |
sh is actually a symbolic link pointing to bash.
The default parser for CentOS is bash:
1 | [root@lht bin]# echo $SHELL |
Shell Script Introduction
Script Format
Shell scripts must specify the parser on the first line, typically starting with #!/bin/bash.
The First Shell Script
Create a directory to store scripts in the home directory:
1 | [root@lht ~]# mkdir scripts |
Create the script file:
1 | [root@lht scripts]# vim hello_world.sh |
In fact, the file extension is not important in Linux, the extension here is just for identification.
Enter the following content in the script file:
1 |
|
Executing the Script
Use the
bashorshcommand with the script’s relative or absolute path to run the script (no need to grant execute permission):1
2[root@lht scripts]# bash hello_world.sh
hello worldActually, this method is just for understanding, since we’ve already specified the script parser in the script file. Using the command to run the script is redundant. The other methods will not be repeated here.
Execute the script by entering the absolute or relative path (must have executable permission).
Check the script file’s status.
Grant execute permission.
Check the system environment.
Most Linux distributions add the user’s home directory’sbindirectory to thePATHvariable. In this case, the corresponding/root/bindirectory is used. If this directory doesn’t exist, create it and place the script file inside.
If we want to add our directory to thePATHvariable, execute the following command:1
[root@lht ~]# export PATH=$PATH:/root/scripts
“/root/scripts” is the directory’s absolute path
1
2[root@lht scripts]# ll hello_world.sh
-rw-r--r-- 1 root root 31 Jun 23 23:50 hello_world.shAs we can see, the script file currently doesn’t have execute permission. Executing it directly via the path will cause an error.
1
2
3[root@lht scripts]# chmod +x hello_world.sh
[root@lht scripts]# ll hello_world.sh
-rwxr-xr-x 1 root root 31 Jun 23 23:50 hello_world.shExecute the script using a relative path:
1
2[root@lht scripts]# ./hello_world.sh
hello worldNote:
./cannot be omitted. If omitted, the system will think you’re typing a command and will search for it in the environment variable, which of course will result in a “command not found” error.1
2[root@lht ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/binOnly commands in these directories can be executed directly from the command line.
1
2
3[root@lht ~]# export PATH=$PATH:/root/scripts
[root@lht ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/scriptsThis environment variable change is valid only for the current session.
1
[root@lht scripts]# vim /etc/profile
Add the following at the end:
1
export PATH=$PATH:/root/scripts
After modifying, you need to refresh the environment variable:
1
[root@lht scripts]# source /etc/profile
Check the environment variable again:
1
2[root@lht scripts]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/scripts:/root/binThe default environment variable is:
1
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
Alternatively, you can add it to the user’s configuration file by adding the above statement to the
~/.bashrcfile.Use
sourceor.to execute the script.
The usage is as follows:
This method mainly differs from the first one in that usingbashorshto run a script opens a child shell by default, where the script is executed. Meanwhile, thesourceand.commands run the script in the current shell.
The difference lies in the environment variable inheritance. Variables set in the child shell are not visible in the parent shell, and changes to environment variables in the child shell only affect the child shell.
Sincebashcommand is not commonly used to run scripts, this method is typically used for understanding purposes. The second method is generally preferred.1
source script_file_path
Or:
1
. script_file_path
This allows the script’s commands to be executed in the current shell environment, making the environment variables defined in the script effective in the current shell.
Variables
System-Defined Variables
Common system variables:
$HOME represents the path of the current user’s home directory.$PWD represents the path of the current working directory.$SHELL represents the path of the current shell being used.$USER represents the current logged-in username.
View the value of system variables
1 | [root@lht scripts]# echo $HOME |
Display all variables in the current shell
1 | [root@lht scripts]# set |
Custom Variables
Basic Syntax
- Define variable: variable_name=variable_value, note that there should be no spaces around the
=sign. - Unset variable: unset variable_name
- Declare a read-only variable: readonly variable, note: it cannot be unset.
If you want to disable a read-only variable, you need to restart the session.
- Define variable: variable_name=variable_value, note that there should be no spaces around the
Variable Definition Rules
- Variable names can consist of letters, numbers, and underscores, but cannot start with a number. It is recommended that environment variable names be uppercase.
- No spaces around the equals sign.
- In Bash, variables are of string type by default and cannot directly perform numeric operations.
- If a variable’s value contains spaces, it needs to be enclosed in double quotes or single quotes.
Practical Examples
Regular variable
1
2
3
4
5
6[root@lht ~]# A=5
[root@lht ~]# echo $A
5
[root@lht ~]# A=6
[root@lht ~]# echo $A
6Read-only variable, cannot be modified or unset
1
2
3
4
5
6
7[root@lht ~]# readonly B=2
[root@lht ~]# echo $B
2
[root@lht ~]# B=3
-bash: B: readonly variable
[root@lht ~]# unset B
-bash: unset: B: cannot unset: readonly variableArithmetic requires using
$[]or$(())1
2
3
4
5
6[root@lht ~]# C=1+2
[root@lht ~]# echo $C
1+2
[root@lht ~]# C=$[1+2]
[root@lht ~]# echo $C
3Values with spaces need to be enclosed in double quotes or single quotes
1
2
3
4
5[root@lht ~]# D=a space
-bash: space: command not found
[root@lht ~]# D="a space"
[root@lht ~]# echo $D
a spacePromote a variable to a global variable
Syntax
1
export variable_name
Modify the previous script file
1
2
3
echo "hello world"
echo $B1
2
3
4
5
6
7[root@lht scripts]# hello_world.sh
hello world
[root@lht scripts]# export B
[root@lht scripts]# hello_world.sh
hello world
2
Special Variables
$n$n(where n is a number) represents parameter variables in a script. Specifically:$0represents the name of the current script.$1to$9represent the first to ninth arguments of the script.- For arguments greater than ten, curly braces are needed, for example,
${10}represents the tenth argument,${11}represents the eleventh argument, and so on.
These parameter variables are used to get the values passed to the script.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@lht scripts]# vim parameter.sh
#!/bin/bash
echo $0
echo $1
echo $2
[root@lht scripts]# chmod +x parameter.sh
[root@lht scripts]# parameter.sh
/root/scripts/parameter.sh
[root@lht scripts]# parameter.sh a b
/root/scripts/parameter.sh
a
b
[root@lht scripts]#$#$#is a special parameter variable used to get the number of input parameters. It is often used in loops, to check if the number of parameters is correct, and to improve the robustness of the script.We can use this feature to write scripts that perform different operations based on the number of parameters. For example, if the number of parameters is not correct, an error message can be displayed, or the user can be reminded to use the script correctly.
Example
1
2
3
4
5if [ $# -ne 2 ]; then
echo "The script requires two parameters!"
echo "Usage: bash script_name param1 param2"
exit 1
fiThis code checks if the number of parameters passed to the script is 2. If not, it displays an error message and exits the script. This improves the robustness of the script, ensuring that the correct number of parameters are passed.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13[root@lht scripts]# vim parameter.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo "---------"
echo $#
[root@lht scripts]# parameter.sh a b c
/root/scripts/parameter.sh
a
b
---------
3$*,$@$*: When enclosed in double quotes"", it treats all command-line arguments as a whole, returning them as a single string.$@: When enclosed in double quotes"", it treats each command-line argument separately, returning each as an individual string.
These variables are commonly used in loops to iterate over command-line arguments.
Here’s an example showing how to use
$*and$@in a loop:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33[root@lht scripts]# vim parameter.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo "---------"
echo $#
# Using $* to loop through arguments
echo "Using \$* to loop through arguments:"
for arg in "$*"; do
echo "$arg"
done
echo
# Using $@ to loop through arguments
echo "Using \$@ to loop through arguments:"
for arg in "$@"; do
echo "$arg"
done
[root@lht scripts]# parameter.sh a b c
/root/scripts/parameter.sh
a
b
---------
3
Using $* to loop through arguments:
a b c
Using $@ to loop through arguments:
a
b
cHere we mentioned loops that have not yet been explained. We will discuss them in detail later. For readers with some programming experience, understanding these commands should not be difficult.
$?$?: The return status of the last executed command.If the value of this variable is 0, it indicates that the previous command was executed successfully.
If the value is non-zero (the specific number is determined by the command itself), it indicates that the previous command failed.
1
2
3
4
5[root@lht scripts]# hello_world.sh
hello world
2
[root@lht scripts]# echo $?
0
Conditional Judgment
Syntax
test condition[ condition ](Note: There must be spaces before and after condition)
Note: A non-empty condition is true, [ content ] returns true, and [ ] returns false.
Common Judgment Conditions
- Comparing two integers:
-eqequals (equal)-nenot equal (not equal)-ltless than (less than)-leless than or equal (less equal)-gtgreater than (greater than)-gegreater than or equal (greater equal)
- Comparing strings:
- Use
=to check for equality. - Use
!=to check for inequality.
- Use
- Checking file permissions:
-rhas read permission (read)-whas write permission (write)-xhas execute permission (execute)
- Checking file types:
-efile exists (existence)-ffile exists and is a regular file (file)-dfile exists and is a directory (directory)
Example
1 | [root@lht scripts]# [ 8 -gt 6 ] |
Flow Control (Key)
if Statement
Syntax
Single branch
1
2
3if [ condition ]; then
program
fiIn one line of command, multiple commands can be entered, separated by semicolons. Thus, the above format is equivalent to:
1
2
3
4if [ condition ]
then
program
fiMultiple branches
1
2
3
4
5
6
7if [ condition ]; then
program
elif [ condition ]; then
program
else
program
fi
Notes:
- There must be spaces between
[ condition ]and the condition expression. - There must be a space after
if.
Example
1 | [root@lht scripts]# vim if.sh |
1 |
|
1 | [root@lht scripts]# chmod +x if.sh |
case Statement
Syntax
1 | case $variable in |
Notes:
- The
caseline must end with the word “in”, and each pattern matching must end with a closing parenthesis). - Double semicolons
;;indicate the end of a command sequence, similar to abreakin Java. - The last
*)represents the default case, similar todefaultin Java.
Example
1 | [root@lht scripts]# vim case.sh |
1 |
|
1 | [root@lht scripts]# chmod +x case.sh |
for Loop
Syntax 1 (Regular for loop)
1 | for (( initial value; loop control condition; variable change )) |
Example
1 | [root@lht scripts]# vim for.sh |
1 |
|
1 | [root@lht scripts]# chmod +x for.sh |
Note: The reason the loop condition can directly use < for comparison is because it is in double parentheses. (( )) represents an arithmetic environment. i=1 is the starting value, i<=101 is the comparison condition, and i++ is the increment operation after each iteration. Conditions in the for loop cannot use square brackets.
Supplementary Explanation
In arithmetic operations, variables can be used directly without the $ symbol for expansion because arithmetic expansion is a special syntax in Shell. Within an arithmetic environment, the Shell automatically recognizes and expands variables.
This behavior differs from general commands, where the $ symbol is needed to expand variables. For example, using echo $variable in the command line will print the value of the variable variable.
However, in an arithmetic environment, the Shell recognizes the variables and treats them as numerical values for computation without explicitly using the $ symbol.
Here is an example demonstrating the use of variables directly in arithmetic operations:
1 | x=5 |
In this example, the variables x and y are directly used in the arithmetic operation, and the Shell automatically expands them and computes the result.
It is important to note that this special variable expansion behavior applies only to arithmetic operations and does not apply to general commands or string manipulation. Therefore, in general commands, the $ symbol is still required to expand a variable to retrieve its value.
Using the above script as an example, it can also be rewritten as:
1 |
|
The output will be the same.
In arithmetic operations, $(()) and $[] are both used for arithmetic expansion in Shell. They serve similar purposes but have some syntactical differences:
$(()): This is a more modern and recommended syntax for arithmetic expansion. Inside$((...)), you can perform mathematical operations, variable assignments, and logical operations. For example:1
2
3x=$((5 + 3)) # Variable x is assigned 8
y=$((x * 2)) # Variable y is assigned 16
z=$((y % 4)) # Variable z is assigned 0$[]: This is an older syntax for arithmetic expansion, which has been deprecated in newer Shell versions. It performs similarly to$(())but does not support logical operators. For example:1
2
3x=$[5 + 3] # Variable x is assigned 8
y=$[x * 2] # Variable y is assigned 16
z=$[y % 4] # Variable z is assigned 0
let is a built-in Shell command used to perform arithmetic operations and variable assignments. It is a more traditional method of performing calculations and differs from $((...)) and $[...] syntax. The general syntax for the let statement is:
1 | let <expression> |
<expression> is the arithmetic expression to be evaluated, which can include variables, mathematical operators, and constants.
Here are some examples showing how to use the let statement for arithmetic operations and variable assignments:
1 | let x=5+3 # Variable x is assigned 8 |
The let statement can also be used to increment or decrement variables:
1 | let counter=1 |
It is important to note that variables in the let statement do not require the $ symbol for reference. You can use the variable names directly. Additionally, let does not support logical operators, and it only supports pure arithmetic operations and variable assignments.
In summary, $(()) is the modern and recommended syntax for arithmetic expansion, offering more functionality and compatibility across most Shell versions. In contrast, $[] is an outdated syntax that does not support logical operators, so it is recommended to use $(()) for arithmetic operations. If the task only involves arithmetic operations and variable assignments, you can also use the let statement, which is more intuitive for users familiar with other programming languages.
Again, using the above script as an example, the script can be written with the let statement as:
1 |
|
This will also produce the correct output.
Syntax 2 (foreach Enhanced For Loop)
The foreach enhanced for loop is used to iterate over a list of values. It provides a more straightforward way to iterate through elements without explicitly managing the loop index. Here’s the syntax for the foreach loop:
1 | for variable in value1 value2 value3... |
Example:
1 | [root@lht scripts]# vim foreach.sh |
1 |
|
When you execute the script, it will produce the sum of numbers from 1 to 100:
1 | [root@lht scripts]# chmod +x foreach.sh |
The foreach loop is a more readable alternative to a standard for loop when you need to iterate over a set of fixed values or a range of numbers.
Difference Between $* and $@
Both $* and $@ are used to represent all the arguments passed to a script or function, but they behave differently when they are enclosed in double quotes.
Without quotes:
When not enclosed in quotes, both$*and$@behave similarly and represent all the positional parameters as a single string, separated by spaces:Example:
1
2
3
4
5
6
7
8
9
10
11
echo "Using \$* to print all arguments:"
for arg in $*; do
echo $arg
done
echo "Using \$@ to print all arguments:"
for arg in $@; do
echo $arg
doneIf you run the script with the arguments
arg1 arg2 arg3:1
$ ./script.sh arg1 arg2 arg3
The output will be:
1
2
3
4
5
6
7
8Using $* to print all arguments:
arg1
arg2
arg3
Using $@ to print all arguments:
arg1
arg2
arg3With quotes:
The difference becomes apparent when you enclose$*and$@in double quotes."$*"treats all the parameters as a single string and outputs them as a single word, separated by spaces."$@"treats each parameter as a separate quoted string.
Example:
1
2
3
4
5
6
7
8
9
10
11
echo "Using \"\$*\" to print all arguments:"
for arg in "$*"; do
echo $arg
done
echo "Using \"\$@\" to print all arguments:"
for arg in "$@"; do
echo $arg
doneIf you run the script with the arguments
arg1 arg2 arg3, the output will be:1
2
3
4
5
6Using "$*" to print all arguments:
arg1 arg2 arg3
Using "$@" to print all arguments:
arg1
arg2
arg3"$*"outputs all the arguments as a single string:arg1 arg2 arg3."$@"outputs each argument separately:arg1,arg2,arg3.
While Loop
The while loop is used for repeated execution of a program as long as a certain condition is true. The syntax is as follows:
1 | while [ condition ] |
Example:
1 |
|
In this example, the loop will continue executing as long as the counter is less than or equal to 5. Each iteration prints the current count and increments the counter.
The output will be:
1 | Loop count: 1 |
The loop will stop when the condition [ $counter -le 5 ] is no longer true. The operator -le stands for “less than or equal” and is used to compare the value of counter to 5.
- Title: Shell Scripts 1
- Author: LHT
- Created at : 2023-01-15 01:10:00
- Link: https://blog.327774.xyz/2023/01/14/linux/shell/Shell Scripts 1/
- License: This work is licensed under CC BY-NC-SA 4.0.