Shell编程实例:手把手教你写第一个脚本

网安智编 厦门萤点网络科技 2026-04-27 00:26 6 0
一、Shell概述——理解Linux的“翻译官” Shell是用户与Linux内核之间的桥梁。当你输入一条命令,Shell负责解释它,并调用操作系统内核执行。你可以把它想象成一位翻译官,把人类的指令“翻译”成内核能理解的机器语言。 1. L...

一、Shell概述——理解Linux的“翻译官”

Shell是用户与Linux内核之间的桥梁。当你输入一条命令,Shell负责解释它,并调用操作系统内核执行。你可以把它想象成一位翻译官,把人类的指令“翻译”成内核能理解的机器语言。

1. Linux支持哪些Shell?

不同的Shell解析器有各自的特点,最常用的是Bash( Again Shell)。查看系统支持哪些Shell:

cat /etc/shells

输出示例:

/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/sh
/bin/dash
/usr/bin/dash

Bash 是大多数Linux发行版的默认Shell,也是我们学习的重点。通过以下命令确认当前使用的Shell:

echo $SHELL
# 输出:/bin/bash

2. Shell的双重身份二、第一个Shell脚本——从Hello World开始1. 脚本格式

每个Shell脚本的第一行必须是 #!/bin/bash,这称为,指定脚本由哪个解释器执行。

2. 编写第一个脚本

创建文件 .sh:

vim helloworld.sh

输入以下内容:

#!/bin/bash
echo "Hello shell!"

保存退出(:wq)。

3. 脚本的两种执行方式方式一:用bash或sh执行(脚本不需要执行权限)方式二:直接执行(脚本必须具有可执行权限)

先添加执行权限:

chmod +x helloworld.sh

然后执行:

./helloworld.sh          # 相对路径
/home/atguigu/helloworld.sh   # 绝对路径

原理:第一种方法是bash解释器帮我们执行脚本,所以脚本本身不需要执行权限;第二种方法是脚本自己作为可执行文件运行,因此必须要有执行权限。

三、变量——脚本的血液1. 系统预定义变量

系统已经定义好的变量,可以直接使用:

使用示例:

echo $PATH   # 查看路径
echo $HOME   # 查看家目录

查看当前Shell中所有变量:set 命令。

2. 自定义变量语法规则变量命名规则名称由字母、数字、下划线组成,不能以数字开头。环境变量名建议大写。等号两侧不能有空格。变量默认类型是字符串,无法直接进行数值运算。若值包含空格,必须用引号括起来(单引号或双引号)。最右侧分号可有可无,一般都不写。案例演示

# 定义变量A,值为5
A=5
echo $A   # 输出:5
# 重新赋值
A=atguigu
echo $A   # 输出:atguigu
# 撤销变量A
unset A
echo $A   # 输出为空
# 定义只读变量B
readonly B=2
echo $B   # 输出:2
B=9       # 报错:bash: B: 只读变量
unset B   # 报错:bash: unset: B: 无法取消设定:只读 variable
# 变量默认是字符串
C=1+2
echo $C   # 输出:1+2(不是3)
# 值包含空格时,必须用引号
D=I love banzhang  # 错误!会报“找不到命令love”
D="I love banzhang"
echo $D   # 输出:I love banzhang

环境变量(全局变量)

使用 可以将自定义变量提升为全局环境变量,使其在子进程中生效。

# 定义一个普通变量
B=3
# 编写脚本helloworld.sh,内容如下:
#!/bin/bash
echo "helloworld"
echo $B
# 执行脚本(未export)
./helloworld.sh
# 输出:helloworld(没有打印B,因为B不是环境变量)
# 导出B为环境变量
export B
./helloworld.sh
# 输出:
# helloworld
# 3

注意:环境变量只在当前进程及其子进程中有效,不同终端窗口之间不共享。

3. 特殊变量

变量

描述

$n

$0表示脚本名称,$1~$9表示第1~9个参数,10以上用$案例:参数变量

创建 .sh:

#!/bin/bash
echo '=========$n========='
echo $0
echo $1
echo $2
echo '=========$#========='
echo $#
echo '=========$*========='
echo $*
echo '=========$@========='
echo $@

执行并观察输出:

./parameter.sh a b c d e f g

输出:

=========$n=========
./parameter.sh
a
b
=========$#=========
7
=========$*=========
a b c d e f g
=========$@=========
a b c d e f g

案例:$?的使用

# 正确命令
./helloworld.sh
echo $?   # 输出:0
# 错误命令
xxx
echo $?   # 输出:127(命令未找到)

四、算术运算符——让脚本会计算

Shell中无法直接进行算术运算,因为变量默认是字符串。必须借助特殊语法。

语法案例

# 计算 (2+3)*4
S=$[(2+3)*4]
echo $S   # 输出:20
# 另一种写法
S=$(((2+3)*4))
echo $S   # 输出:20

五、条件判断——让脚本有决策能力1. 语法格式

返回值:条件成立(数据非空)返回0(真),否则返回1(假)。

test
echo $?   # 输出:1(空字符串,假)
[ ]
echo $?   # 输出:1
test abc
echo $?   # 输出:0
[ abc ]
echo $?   # 输出:0

2. 常用判断条件整数比较(不能直接用 > < 等符号)

$#

获取所有输入参数的个数

$*

所有参数,作为一个整体

$@

所有参数,每个参数独立

上一条命令的返回状态,0表示成功,非0表示失败

案例:参数变量

创建 .sh:

#!/bin/bash
echo '=========$n========='
echo $0
echo $1
echo $2
echo '=========$#========='
echo $#
echo '=========$*========='
echo $*
echo '=========$@========='
echo $@

执行并观察输出:

./parameter.sh a b c d e f g

输出:

=========$n=========
./parameter.sh
a
b
=========$#=========
7
=========$*=========
a b c d e f g
=========$@=========
a b c d e f g

案例:$?的使用

# 正确命令
./helloworld.sh
echo $?   # 输出:0
# 错误命令
xxx
echo $?   # 输出:127(命令未找到)

四、算术运算符——让脚本会计算

Shell中无法直接进行算术运算,因为变量默认是字符串。必须借助特殊语法。

语法案例

# 计算 (2+3)*4
S=$[(2+3)*4]
echo $S   # 输出:20
# 另一种写法
S=$(((2+3)*4))
echo $S   # 输出:20

五、条件判断——让脚本有决策能力1. 语法格式

返回值:条件成立(数据非空)返回0(真),否则返回1(假)。

test
echo $?   # 输出:1(空字符串,假)
[ ]
echo $?   # 输出:1
test abc
echo $?   # 输出:0
[ abc ]
echo $?   # 输出:0

2. 常用判断条件整数比较(不能直接用 > < 等符号)文件权限判断文件类型判断3. 案例

# 整数比较
[ 22 -lt 23 ]
echo $?   # 0
# 文件权限
[ -w helloworld.sh ]
echo $?   # 0
# 文件存在
[ -e helloworld.sh ]
echo $?   # 0
# 多条件判断(&& 前一个命令成功才执行后一个,|| 前一个失败才执行后一个)
[ atguigu ] && echo OK || echo notOK   # 输出:OK
[ ] && echo OK || echo notOK           # 输出:notOK

六、流程控制——让脚本智能化1. if判断单分支

if [ 条件判断式 ]; then
    程序
fi

或(换行写):

if [ 条件判断式 ]
then
    程序
fi

多分支

if [ 条件判断式 ]; then
    程序
elif [ 条件判断式 ]; then
    程序
else
    程序
fi

注意:

案例:年龄判断

#!/bin/bash
if [ $# -eq 0 ]; then
    echo "请携带年龄"
elif [ $1 -lt 18 ]; then
    echo "未成年人"
elif [ $1 -lt 60 ]; then
    echo "成年人"
else
    echo "老年人"
fi

执行测试:

chmod +x if.sh
./if.sh 12   # 输出:未成年人
./if.sh 34   # 输出:成年人
./if.sh 66   # 输出:老年人
./if.sh      # 输出:请携带年龄

2. case语句

用于多分支选择,类似C语言的。

语法

case $变量名 in
"值1")
    程序1
    ;;
"值2")
    程序2
    ;;
*)
    默认程序
    ;;
esac

注意:

案例:数字对应角色

#!/bin/bash
case $1 in
"1")
    echo "banzhang"
    ;;
2)
    echo "cls"
    ;;
*)
    echo "renyao"
    ;;
esac

执行:

./case.sh 1   # banzhang
./case.sh 2   # cls
./case.sh 3   # renyao

3. for循环语法1:C语言风格

for ((初始值;循环控制条件;变量变化))
do
    程序
done

案例:1加到100

#!/bin/bash
sum=0
for((i=1;i<=100;i++))
do
    sum=$[sum+$i]
done
echo $sum   # 输出:5050

语法2:遍历列表

for 变量 in 值1 值2 值3...
do
    程序
done

案例:打印列表

#!/bin/bash
for i in cls mly wls
do
    echo "ban zhang love $i"
done

输出:

ban zhang love cls
ban zhang love mly
ban zhang love wls

深入:$* 与 $@ 的区别

案例对比:

#!/bin/bash
echo '=========$*========='
for i in "$*"
do
    echo "ban zhang love $i"
done
echo '=========$@========='
for j in "$@"
do
    echo "ban zhang love $j"
done

执行:

./for4.sh cls mly wls

输出:

=========$*=========
ban zhang love cls mly wls
=========$@=========
ban zhang love cls
ban zhang love mly
ban zhang love wls

4. while循环语法

while [ 条件判断式 ]
do
    程序
done

案例:1加到100

#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
    sum=$[sum+$i]
    i=$[i+1]
done
echo $sum   # 输出:5050

七、read命令——实现交互式输入1. 作用

从终端读取用户输入,存入变量。

2. 语法

read

变量名

常用选项:

3. 案例

#!/bin/bash
read -t 7 -p "Enter your name in 7 seconds: " NAME
echo $NAME

执行后,会等待用户输入最多7秒,输入的内容存入NAME变量,并打印出来。

八、函数——模块化编程1. 自定义函数语法

[ function ] funname()
{
    Action;
    [return int;]
}

注意事项:

必须在调用函数之前先声明函数(Shell脚本是逐行执行的)。函数返回值通过 $? 获取,可以显式使用 返回数值(0-255),如果不加,则以最后一条命令的执行结果作为返回值。函数可以带参数,参数在函数内部用 $1、$2 等获取。2. 案例:计算两个数的和

#!/bin/bash
sum()
{
    SUM=$[$1+$2]
    echo $SUM
}
read -p "请输入第一个数值:" n1
read -p "请输入第二个数值:" n2
sum $n1 $n2

九、Shell工具——文本处理三剑客1. cut——列提取工具

cut 命令用于从文件的每一行中剪切出指定的部分。

语法

cut

选项参数

常用选项:

案例

# 准备数据
vim cut.txt
dong shen
guan zhen
wo wo1
lai lai1
le le1
# 1. 切割第一列
cut -d " " -f 1 cut.txt
# 输出:
dong
guan
wo
lai
le
# 2. 切割第二、三列
cut -d " " -f 2,3 cut.txt
# 输出:
shen
zhen
wo1
lai1
le1
# 3. 切割出包含guan的那一行
cat cut.txt | grep guan | cut -d " " -f 1
# 输出:guan
# 4. 从PATH变量中提取第3个冒号之后的所有路径
echo $PATH | cut -d ":" -f 3-
# 输出:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
# 5. 提取IP地址(以ifconfig为例)
ifconfig ens33 | grep netmask | cut -d "i" -f 2 | cut -d " " -f 2
# 输出:192.168.10.150

2. awk——强大的文本分析工具

awk 逐行读入文件,以空格为默认分隔符,对每行切片处理。

语法

awk

选项参数

'//{}'

常用选项:

内置变量案例

# 准备数据:复制passwd文件
cp /etc/passwd ./passwd
# 1. 搜索以root开头的行,输出第7列
awk -F: '/^root/{print $7}' passwd
# 输出:/bin/bash
# 2. 输出第1列和第7列,用逗号分隔
awk -F: '/^root/{print $1","$7}' passwd
# 输出:root,/bin/bash
# 3. 在所有行前添加列名,行尾添加自定义内容
awk -F: 'BEGIN{print "user, shell"} {print $1","$7} END{print "atguigu, bin/zuishuai"}' passwd
# 4. 用户ID增加1
awk -v i=1 -F: '{print $3+i}' passwd
# 5. 统计信息
awk -F: '{print "filename:" FILENAME ",linenum:" NR ",col:" NF}' passwd
# 6. 查询空行行号
ifconfig | awk '/^$/ {print NR}'
# 7. 提取IP地址(另一种方法)
ifconfig ens33 | awk -F " " '/inet /{print $2}'

十、正则表达式入门——模式匹配的利器

正则表达式用于描述、匹配符合规则的字符串。在Linux中,grep、sed、awk等都支持正则表达式。

1. 常规匹配

普通字符匹配自身。例如:

cat /etc/passwd | grep atguigu

匹配所有包含“”的行。

2. 常用特殊字符

字符

说明

示例

匹配行首

^a 匹配以a开头的行

匹配行尾

n$ 匹配以n结尾的行

匹配任意单个字符

r...t 匹配r和t之间有3个任意字符

匹配前一个字符0次或多次

ro*t 匹配rt, rot, root等

匹配括号内的任意一个字符

匹配一个数字

转义特殊字符

a\$b 匹配包含a$b的行

实战

# 匹配以a开头的行
cat /etc/passwd | grep ^a
# 匹配以n结尾的行
cat /etc/passwd | grep n$
# 匹配包含r开头,t结尾,中间任意3个字符
cat /etc/passwd | grep r...t
# 匹配ro*t(r后跟0个或多个o,再跟t)
cat /etc/passwd | grep ro*t
# 匹配包含数字的行
cat /etc/passwd | grep [0-9]
# 匹配包含特殊字符$的行(需要转义)
cat /etc/passwd | grep a\$b

3. 经典正则表达式

邮箱正则:

^[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+$

手机号正则(简单):

^1[3-9]\d{9}$

4. 正则表达式语法补充总结

通过这篇超详细的教程,我们从零开始全面学习了Shell脚本的核心知识:

Shell脚本是Linux运维开发的核心技能之一,掌握它,你将能够:

建议你动手敲一遍所有案例,在实践中加深理解。遇到问题时,善用echo和set -x进行调试。坚持练习,你很快就能成为Shell脚本高手!

下一步:可以尝试编写一个综合脚本,比如备份日志、监控服务器资源、批量创建用户等,将所学知识融会贯通。祝你学习愉快!

shell编程实例_Linux Shell基础教程_Shell脚本入门教程