# Shell脚本编写
参照《Linux命令行大全》一书,学习如何编写Shell脚本。
# 第一个脚本-HelloWorld
[root@VM-8-5-centos shells]# ls
hello_world.sh
[root@VM-8-5-centos shells]# cat hello_world.sh
#!/bin/bash
# This is the first shell
echo 'Hello World!'
[root@VM-8-5-centos shells]# sh hello_world.sh
Hello World!
# 在脚本中使用变量及常量
[root@VM-8-5-centos shells]# > sys_info_page.sh
[root@VM-8-5-centos shells]# vim sys_info_page.sh
[root@VM-8-5-centos shells]# cat sys_info_page.sh
#!/bin/sh
#在shell中添加变量及使用环境变量
TITLE="System Information Report For $HOSTNAME"
echo "<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
</body>
</html>"
[root@VM-8-5-centos shells]# sh sys_info_page.sh
<html>
<head>
<title>System Information Report For VM-8-5-centos</title>
</head>
<body>
<h1>System Information Report For VM-8-5-centos</h1>
</body>
</html>
# 在脚本中使用Shell函数
[root@VM-8-5-centos shells]# cat sys_info_page.sh
#!/bin/sh
#在shell中添加变量及使用环境变量
TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME="$(date +"%x %r %Z")"
TIMESTAMP="Generated $CURRENT_TIME, by $USER"
report_uptime(){
# _EOF_块中间一定不能出现空格
cat <<-_EOF_
<h2>System Uptime</h2>
<pre>$(uptime)</pre>
_EOF_
return
}
report_disk_space(){
cat <<-_EOF_
<h2>Disk Space Utilization</h2>
<pre>$(df -h)</pre>
_EOF_
return
}
report_home_space(){
cat <<-_EOF_
<h2>Home Space Utilization</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
return
}
echo "<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIMESTAMP</p>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</body>
</html>"
[root@VM-8-5-centos shells]# sh sys_info_page.sh
<html>
<head>
<title>System Information Report For VM-8-5-centos</title>
</head>
<body>
<h1>System Information Report For VM-8-5-centos</h1>
<p>Generated 01/15/2024 04:05:47 PM CST, by root</p>
<h2>System Uptime</h2>
<pre> 16:05:47 up 23 days, 17:59, 2 users, load average: 0.00, 0.01, 0.05</pre>
<h2>Disk Space Utilization</h2>
<pre>Filesystem Size Used Avail Use% Mounted on
devtmpfs 908M 0 908M 0% /dev
tmpfs 919M 24K 919M 1% /dev/shm
tmpfs 919M 664K 919M 1% /run
tmpfs 919M 0 919M 0% /sys/fs/cgroup
/dev/vda1 50G 4.9G 43G 11% /
tmpfs 184M 0 184M 0% /run/user/0
overlay 50G 4.9G 43G 11% /var/lib/docker/overlay2/1d84ba15ebf6364747fbcfd77cde318d291d35056382d522237b39b7405ad914/merged</pre>
<h2>Home Space Utilization</h2>
<pre>40K /home/lighthouse</pre>
</body>
</html>
# 在脚本中使用流控制-if判断
if判断的语法是一个if关键词后配置一个test表达式形式,如if [-b file] 判断指定文件是否是一个块文件。如if [[ expression ]]。如(())表达式用于执行算数真值测试。
- 文件表达式
表达式 | 说明 |
---|---|
file1 -ef file2 | file1和file2拥有相同的信息节点编号(这两个文件通过硬链接指向同一个文件)。 |
file1 -nt file2 | file1比file2新。 |
file1 -ot file2 | file1比file2旧。 |
-b file | file存在并且是一个块设备文件。 |
-c file | file存在且是一个字符设备文件。 |
-d file | file存在且是一个目录。 |
-e file | file存在。 |
-f file | file存在且是一个普通文件。 |
-g file | file存在且设置了组id。 |
-G file | file存在且设置了有效组id。 |
-L file | file存在且是一个符号链接。 |
-O file | file存在且属于有效用户id。 |
-p file | file存在且是一个命名管道。 |
-r file | file存在且可读。 |
-s file | file存在并且其长度大于0。 |
-S file | file存在且是一个网络套接字(Socket)。 |
-w file | file存在并且可写。 |
-x file | file存在并且可执行。 |
- 字符串表达式
表达式 | 说明 |
---|---|
string | string不为空。 |
-n string | string的长度大于0。 |
-z string | string的长度等于0。 |
string1==string2 | string1和string2相等。 |
string1!=string2 | string1和string2不相等。 |
string1>string2 | 在排序时,string1在string2之后。 |
- 整数表达式
表达式 | 说明 |
---|---|
int1 -eq int2 | int1和int2相等。 |
int1 -ne int2 | int1和int2不相等。 |
int1 -le int2 | int1小于等于int2。 |
int1 -lt int2 | int1小于int2。 |
int1 -ge int2 | int1大于等于int2。 |
int1 -gt int2 | int1大于int2。 |
[root@VM-8-5-centos shells]# cat testif.sh
#!/bin/bash
x=5
# 需要注意,[后面和]前面必须要有空格
if [ $x -eq 5 ];then
echo "x equals 5"
else
echo "x not equals 5"
fi
[root@VM-8-5-centos shells]# sh testif.sh
x equals 5
[root@VM-8-5-centos shells]# cat test_file.sh
#!/bin/bash
FILE=~/.bashrc
# if 和 [ 之间也要加空格,不然会报错
if [ -e "$FILE" ];then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
else
echo "$FILE does not exist"
exit 1
fi
# 退出
exit
[root@VM-8-5-centos shells]# sh test_file.sh
/root/.bashrc is a regular file.
/root/.bashrc is readable.
/root/.bashrc is writable.
[root@VM-8-5-centos shells]# cat test_string.sh
#!/bin/bash
ANSWER=maybe
if [ -z "$ANSWER" ]; then
echo "There is no answer." >&2
exit 1
fi
if [ "$ANSWER" = "yes" ]; then
echo "The answer is yes."
elif [ "$ANSWER" = "no" ]; then
echo "The answer is no."
elif [ "$ANSWER" = "maybe" ]; then
echo "The answer is maybe."
else
echo "The answer is unknown."
fi
[root@VM-8-5-centos shells]# sh test_string.sh
The answer is maybe.
[root@VM-8-5-centos shells]# cat test_int.sh
#!/bin/bash
INT=5
if [ -z "$INT" ]; then
echo "INT is empty." >&2
exit 1
fi
if [ "$INT" -eq 0 ]; then
echo "INT is zero."
else
if [ "$INT" -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
[root@VM-8-5-centos shells]# sh test_int.sh
INT is positive.
INT is odd.
[root@VM-8-5-centos shells]# cat test_int2.sh
#!/bin/bash
INT=5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [ "$INT" -eq 0 ]; then
echo "INT is zero."
else
if [ "$INT" -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi
[root@VM-8-5-centos shells]# sh test_int2.sh
INT is positive.
INT is odd.
[root@VM-8-5-centos shells]# cat test_int3.sh
#!/bin/bash
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if ((INT == 0)); then
echo "INT is zero."
else
if (( INT < 0)); then
echo "INT is negative."
else
echo "INT is positive."
fi
if (( ((INT % 2)) == 0)); then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi
[root@VM-8-5-centos shells]# sh test_int3.sh
INT is negative.
INT is odd.
# 在脚本中读取键盘输入
使用read指令,可以从标准输入中读取输入值。
- read指令相关选项
选项 | 说明 |
---|---|
-a array | 将输入值从索引为0的位置开始赋值给array数组。 |
-d delimiter | 用字符串delimiter的第一个字符标志输入的结束,而不是新的一行的开始。 |
-n num | 从输入中读取num个字符,而不是一整行。 |
-p prompt | 使用prompt字符串提示用户进行输入。 |
-s | 保密模式,不在屏幕显示输入的字符。 |
-t seconds | 超时。在seconds秒后结束输入。 |
[root@VM-8-5-centos shells]# cat read_int.sh
#!/bin/bash
echo -n "Please enter an int. -> "
read INT
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [ "$INT" -eq 0 ]; then
echo "INT is zero."
else
if [ "$INT" -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fi
[root@VM-8-5-centos shells]# sh read_int.sh
Please enter an int. -> 3
INT is positive.
INT is odd.
# 在脚本中使用流控制-while循环
[root@VM-8-5-centos shells]# cat while_count.sh
#!/bin/bash -x
count=1
while [ $count -le 5 ]; do
echo $count
count=$((count + 1))
done
echo "Finished."
[root@VM-8-5-centos shells]# sh while_count.sh
1
2
3
4
5
Finished.
[root@VM-8-5-centos shells]# cat while-menu2.sh
#!/bin/bash
DELAY=3
while true;do
clear
cat <<- _EOF_
Please Select:
1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
Q.Quit
_EOF_
read -p "Enter Selection [0-3] >"
if [[ $REPLY =~ ^[0-3]$ ]];then
if [[ $RELAY == 1 ]];then
echo "Hostname: $HOSTNAME"
uptime
sleep $DELAY
continue;
fi
if [[ $RELAY == 2 ]];then
df -h
sleep $DELAY
continue;
fi
if [[ $REPLY == 3 ]];then
echo "hello"
sleep $DELAY
continue;
fi
if [[ $REPLY == 0 ]];then
break;
fi
else
echo "Invalid entry."
sleep $DELAY
fi
done
echo "Program terminated."
# 在脚本中使用流控制-case分支
[root@VM-8-5-centos shells]# cat case-menu.sh
#!/bin/bash
clear
echo "
Please Select:
1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
Q.Quit
"
read -p "Enter Selection [0-3] >"
case $REPLY in
0) echo "Program terminated."
exit
;;
1) echo "Hostname: $HOSTNAME"
uptime
;;
2) df -h
;;
3) echo "hello"
exit 1
;;
esac
[root@VM-8-5-centos shells]# sh case-menu.sh
Please Select:
1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
Q.Quit
Enter Selection [0-3] >2
Filesystem Size Used Avail Use% Mounted on
devtmpfs 908M 0 908M 0% /dev
tmpfs 919M 24K 919M 1% /dev/shm
tmpfs 919M 640K 919M 1% /run
tmpfs 919M 0 919M 0% /sys/fs/cgroup
/dev/vda1 50G 4.9G 43G 11% /
tmpfs 184M 0 184M 0% /run/user/0
overlay 50G 4.9G 43G 11% /var/lib/docker/overlay2/1d84ba15ebf6364747fbcfd77cde318d291d35056382d522237b39b7405ad914/merged
# 在脚本中使用位置参数
[root@VM-8-5-centos shells]# cat posit-param.sh
#!/bin/bash
echo "
Number of arguments: $#
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
"
[root@VM-8-5-centos shells]# sh posit-param.sh
Number of arguments: 0
$0 = posit-param.sh
$1 =
$2 =
$3 =
$4 =
$5 =
$6 =
$7 =
$8 =
$9 =
[root@VM-8-5-centos shells]# sh posit-param.sh 1 2 3
Number of arguments: 3
$0 = posit-param.sh
$1 = 1
$2 = 2
$3 = 3
$4 =
$5 =
$6 =
$7 =
$8 =
$9 =
# 在脚本中使用流控制-for循环
[root@VM-8-5-centos shells]# cat simple_count.sh
#!/bin/bash
for (( i=0; i<5; i=i+1 )); do
echo $i
done
[root@VM-8-5-centos shells]# sh simple_count.sh
0
1
2
3
4