Linux学习之旅之Shell 脚本(一)

一、认识Shell

1、什么是Shell

Shell 是用户和操作系统内核之间的「命令解释器」,相当于一层外壳,把人类输入的命令翻译给内核执行,再把内核结果返回给用户。

2、常见Shell

Shell说明
bash (/bin/bash)现在 Linux 默认 Shell,功能最强,日常写.sh脚本绝大多数用 bash
sh (/bin/sh)POSIX 标准 shell,语法精简,功能受限;很多系统 sh 是 bash 的软链接
zsh交互体验好,运维终端常用(oh‑my‑zsh)
csh/tcshC 语言风格语法,很少写脚本用

二、Shell基础规则

1、解释器声明

#! 叫做 shebang,必须写在文件第一行,告诉系统用 bash 解释执行脚本。
#!/bin/bash

2、文件权限与执行方式

#新建脚本 data.sh
root@ubuntu2404ser:~# vim date.sh
root@ubuntu2404ser:~# cat date.sh
#!/bin/bash
date




# 方式1:推荐,使用脚本内shebang指定解释器
root@ubuntu2404ser:~# ll date.sh
-rw-r--r-- 1 root root 17 Aug 24 02:46 date.sh
root@ubuntu2404ser:~# ./date.sh
-bash: ./date.sh: Permission denied

# 赋予可执行权限
root@ubuntu2404ser:~# chmod +x date.sh
root@ubuntu2404ser:~# ll date.sh
-rwxr-xr-x 1 root root 17 Aug 24 02:46 date.sh*
root@ubuntu2404ser:~# ./date.sh
Mon Aug 24 02:49:07 AM UTC 2026


# 方式2:直接指定解释器执行,不需要x权限

root@ubuntu2404ser:~# /bin/bash date.sh
Mon Aug 24 02:47:19 AM UTC 2026


# 方式3:在当前shell执行(会改变当前shell环境变量)
root@ubuntu2404ser:~# chmod -x date.sh
root@ubuntu2404ser:~# ll date.sh
-rw-r--r-- 1 root root 17 Aug 24 02:46 date.sh
root@ubuntu2404ser:~# source date.sh
Mon Aug 24 02:49:54 AM UTC 2026

3、本地变量

本地变量:只在当前 Shell 环境内生效,不会传给子 Shell,脚本结束就销毁,其它终端没有办法使用

root@ubuntu2404ser:~# tty
/dev/pts/0

root@ubuntu2404ser:~# name=xyx
root@ubuntu2404ser:~# echo $name
xyx


root@ubuntu2404ser:~# tty
/dev/pts/1
root@ubuntu2404ser:~# echo $name

root@ubuntu2404ser:~#

4、全局变量

通告所有终端

root@ubuntu2404ser:~# tty
/dev/pts/0
root@ubuntu2404ser:~# echo 'export myvar="hello123"' >> /root/.bashrc
root@ubuntu2404ser:~# echo $myvar
hello123


root@ubuntu2404ser:~# tty
/dev/pts/1
root@ubuntu2404ser:~# source .bashrc
root@ubuntu2404ser:~# echo $myvar
hello123

5、变量命名规则

1. 只能由字母、数字、下划线组成

root@ubuntu2404ser:~# n_b=123
root@ubuntu2404ser:~# echo $n_b
123

root@ubuntu2404ser:~# n-n=1234
n-n=1234: command not found

2. 不能以数字开头

root@ubuntu2404ser:~# 1mmm=yyy
1mmm=yyy: command not found


3. 区分大小写:A 和 a 是两个完全不同变量

root@ubuntu2404ser:~# ncs=hhh
root@ubuntu2404ser:~# echo $ncs
hhh

root@ubuntu2404ser:~# NCS=yyy
root@ubuntu2404ser:~# echo $NCS
yyy

4. 等号 = 两边绝对不能加空格

root@ubuntu2404ser:~# aaa = bbb
Command 'aaa' not found, did you mean:
.................
Try: apt install <deb name>


5. 字符串,无空格可以不加引号
root@ubuntu2404ser:~# var=abc
root@ubuntu2404ser:~# echo $var
abc


6. 值包含空格、特殊符号,必须加双引号 ""
root@ubuntu2404ser:~# var="hello world"
root@ubuntu2404ser:~# echo $var
hello world


7. 单引号 '':原样输出,不解析$变量
root@ubuntu2404ser:~# var='echo $HOME'
root@ubuntu2404ser:~# echo $var
echo $HOME


8. 双引号“” :解析$变量

root@ubuntu2404ser:~# var="echo $HOME"
root@ubuntu2404ser:~# echo $var
echo /root


8. $() 命令执行结果赋值
root@ubuntu2404ser:~# res=$(ls /root)
root@ubuntu2404ser:~# echo $res
date.sh xyy.sh


9. 反引号 `` 等价 $(),旧写法
root@ubuntu2404ser:~# res=`pwd`
root@ubuntu2404ser:~# echo $res
/root

6、{}使用方式

$变量名 简单使用
${变量名} 推荐,用于拼接,避免边界混淆

root@ubuntu2404ser:~# a=10
root@ubuntu2404ser:~# echo $a
10
root@ubuntu2404ser:~# echo ${a}
10


root@ubuntu2404ser:~# prefix="test"
root@ubuntu2404ser:~# file="${prefix}_log.txt"
root@ubuntu2404ser:~# echo $file
test_log.txt

三、环境变量

1、$0

#显示脚本 / 程序名字
root@ubuntu2404ser:~# cat > "test.sh" << 'EOF'
> #!/bin/bash
echo "脚本名 $0"
> EOF
root@ubuntu2404ser:~# bash test.sh
脚本名 test.sh

2、$1~n

# $1 ~ $9 :脚本第 1 至第 9 个传入参数,超过 9 个参数需使用 ${10} 、 ${11} 大括号写法读取

root@ubuntu2404ser:~# vim test.sh
root@ubuntu2404ser:~# cat test.sh
#!/bin/bash
echo "脚本名称:$0"
echo "第1个参数:$1"
echo "第2个参数:$2"
echo "第10个参数:${10}"
echo "参数总个数: $#""

root@ubuntu2404ser:~# bash test.sh sshd 22
脚本名称:test.sh
第1个参数:sshd
第2个参数:22
第10个参数:
参数总个数: 2

root@ubuntu2404ser:~# bash test.sh a b c d e f g h i j k l m n
脚本名称:test.sh
第1个参数:a
第2个参数:b
第10个参数:j
参数总个数: 14

3、$#

$# :统计脚本传入参数总个数,常用于前置校验参数数量是否符合要求。

root@ubuntu2404ser:~# bash test.sh a b c d e f g h i j k l m n
参数总个数: 14

4、$*

$* :把所有参数合并为单个完整字符串,参数之间以 IFS 分隔符(默认空格)拼接。


root@ubuntu2404ser:~# vim test.sh
root@ubuntu2404ser:~# cat test.sh
#!/bin/bash
echo '==== "$*" 输出 ===='
for arg in "$*"; do
  echo "参数项:$arg"
done
root@ubuntu2404ser:~#


root@ubuntu2404ser:~# bash test.sh a b c d
==== "$*" 输出 ====
参数项:a b c d e f

5、$@

 $@ :保留参数原始独立数组结构,每个参数单独隔离,带空格的参数不会被拆分。
root@ubuntu2404ser:~# vim test.sh
root@ubuntu2404ser:~# cat test.sh
#!/bin/bash
echo '==== "$@" 输出 ===='
for arg in "$@"; do
  echo "参数项:$arg"
done
root@ubuntu2404ser:~# bash test.sh a b c d e f
==== "$@" 输出 ====
参数项:a
参数项:b
参数项:c
参数项:d
参数项:e
参数项:f
root@ubuntu2404ser:~#

6、$?

$? :上一条执行命令的退出返回码,0 代表执行成功,非 0 代表异常失败。

root@ubuntu2404ser:~# ls ./
date.sh  test.sh  xyy.sh
root@ubuntu2404ser:~# echo $?
0

root@ubuntu2404ser:~# sklab
sklab: command not found
root@ubuntu2404ser:~# echo $?
127

7、$$

$$ :当前脚本运行进程 PID,常用于临时文件命名、进程唯一标识。

root@ubuntu2404ser:~# echo $$
2629
root@ubuntu2404ser:~# tty
/dev/pts/1
root@ubuntu2404ser:~# ps aux |grep 2629
root        2629  0.0  0.3   8780  5872 pts/1    Ss   03:15   0:00 -bash

8、$!

$! :上一个后台异步执行命令(&)的进程 PID,用于后台进程监控、等待后台任务。

root@ubuntu2404ser:~# sleep 200 &
[1] 2922
root@ubuntu2404ser:~# echo $!
2922
root@ubuntu2404ser:~# ps aux | grep "sleep"
root        2922  0.0  0.1   5684  2104 pts/1    S    05:00   0:00 sleep 200

四、输入输出

1、echo输出

-n:不换行输出
-e:开启转义字符解析(\n换行、\t制表符、\\反斜杠)
root@ubuntu2404ser:~# echo "hello word"
hello word

root@ubuntu2404ser:~# echo -n "请输入开机密码: "
请输入开机密码: root@ubuntu2404ser:~#

root@ubuntu2404ser:~# echo -e "第一行\n第二行\n第三行\n "
第一行
第二行
第三行


#-e颜色解析

root@ubuntu2404ser:~# echo -e "\033[31m红色\033[0m"
红色

root@ubuntu2404ser:~# echo -e "\033[32m绿色\033[0m"
绿色

root@ubuntu2404ser:~# echo -e "\033[33m黄色\033[0m"
黄色

字体颜色

代码颜色
30黑色
31红色(错误)
32绿色(成功)
33黄色(警告)
34蓝色
35紫色
36青色
37白色

背景颜色

代码颜色
40黑背景
41红背景
42绿背景
43黄背景
44蓝背景

2、read 读取用户输入(接收键盘输入)

-p "提示文字":打印提示,不用额外写 echo
-t 5:超时 5 秒,没有输入自动结束
-s:静默输入,输入不回显(密码输入)
-n 3:只读取 3 个字符,输完直接结束,不用回车root@ubuntu2404ser:~# read -p "请输入新的主机名:" hostname
请输入新的主机名:xyx


root@ubuntu2404ser:~# read -s -p "请输入密码:" passwd
请输入密码:root@ubuntu2404ser:~#

#等待三秒
root@ubuntu2404ser:~# read -t 3 -p  "请输入密码:" passwd
请输入密码:root@ubuntu2404ser:~#

3、printf 格式化

%s :字符串占位,输出文本、路径、服务名称;
%d :十进制整数占位,输出端口、进程号、使用率整数;
%6.2f :浮点数格式化,总宽度 6 位,保留 2 位小数,自动空格补齐实现右对齐。

#不支持自动换行
root@ubuntu2404ser:~# printf "你的名字是: %s\n" "XYX"
你的名字是: XYX
root@ubuntu2404ser:~# printf "你的名字是: %s" "XYX"
你的名字是: XYXroot@ubuntu2404ser:~#

#问就是永远18
root@ubuntu2404ser:~# printf "你的年龄: %d\n" "18"
你的年龄: 18
root@ubuntu2404ser:~#

#%A.Bf 浮点数格式规则:
#A:总字段宽度(整个数字占多少字符,包含小数点)
#B:小数点后面保留多少位小数

root@ubuntu2404ser:~# printf "你的存款多少: %6.3f元\n" "58.62"
你的存款多少: 58.620

五、条件判断体系

判断含义
-eq等于
-ne不等于
-gt大于
-ge大于等于
-lt小于
-le小于等于

1、test

#明显不对,因为=是字符串比较运算符,运算符两边必须是独立参数,要有空格隔开!
root@ubuntu2404ser:~# test 1=2
root@ubuntu2404ser:~# echo $?
0
root@ubuntu2404ser:~# test 1 = 2
root@ubuntu2404ser:~# echo $?
1

#判断文件是否存在
root@ubuntu2404ser:~# test -f test.sh
root@ubuntu2404ser:~# echo $?
0
root@ubuntu2404ser:~# ls
date.sh  test.sh  xyy.sh

#判断相等
root@ubuntu2404ser:~# test "a" = "b"
root@ubuntu2404ser:~# echo $?
1

2、[ ]

#[ ] 等价于 test

#[ b ]括号内侧必须有空格
root@ubuntu2404ser:~# [a = b]
[a: command not found

root@ubuntu2404ser:~# [ a = b ]
root@ubuntu2404ser:~# echo $?
1

root@ubuntu2404ser:~# [ -f /etc/passwd ]
root@ubuntu2404ser:~# echo $?
0
表达式含义
-f file普通文件存在
-d file目录存在
-e file文件 / 目录存在
-r file可读
-w file可写
-x file可执行

3、[[ ]]

[[ ]] 是 bash 专属扩展判断语法,不属于 POSIX 标准,仅 bash 环境可用,运维脚本首选。

支持:&&、||、>、<、=~正则匹配

写法逻辑与逻辑或
[ ] / test-a-o
[[ ]]&&

root@ubuntu2404ser:~# [[ 1 -eq 1 && 1 -ne 2 ]]
root@ubuntu2404ser:~# echo $?
0

root@ubuntu2404ser:~# [[ "a" -ne "b" || "a" -eq "b" ]]
root@ubuntu2404ser:~# echo $?
0

root@ubuntu2404ser:~# port="4399"
root@ubuntu2404ser:~# [[ ${port} =~ ^[0-9]*$ ]]
root@ubuntu2404ser:~# echo $?
0
root@ubuntu2404ser:~#

4、== != -n -e

运算符含义适用场景
=字符串相等[ ][[ ]]
==字符串相等[[ ]][ ]不标准
!=字符串不相等[ ][[ ]]
-z 字符串长度为 0([ ][[ ]]
-n 字符串长度不为 0(非空[ ][[ ]]
root@ubuntu2404ser:~# [[ "hello" == "hello" ]]
root@ubuntu2404ser:~# echo $?
0
root@ubuntu2404ser:~# [[ "hello" != "hello" ]]
root@ubuntu2404ser:~# echo $?
1

root@ubuntu2404ser:~# [ -z "$NAME" ]
root@ubuntu2404ser:~# echo $?
0

root@ubuntu2404ser:~# [ -n "$HOME" ]
root@ubuntu2404ser:~# echo $?
0

六、流程控制

1、if 分支

#单分支 if 语法结构: if 判断条件; then 条件成立执行代码; fi , fi 是 if 的反向结束标记,必须成对出现。

#; 分号作用:将 if 与 then 写在同一行,分隔两条独立语句;也可换行省略分号。

#缩进规范:then 内部执行代码统一缩进 n 空格,企业脚本标准化排版,提升可读性。

#适用场景:前置参数校验、文件目录存在性判断、资源阈值告警单次判断。
#标准用法,增加可读性
if 条件;then
    命令
elif 条件2;then
    命令
else
    命令
fi

#单分支

root@ubuntu2404ser:~# vim test.sh
#!/bin/bash
read -p "输入数字:" num
if [[ $num -gt 100 ]];then
    echo "大于100"
fi
root@ubuntu2404ser:~# bash test.sh
请输入数字: 111
数字大于100

#多分支
root@ubuntu2404ser:~# vim test.sh
#!/bin/bash
read -p "输入数字:" num
if [[ $num -gt 100 ]];then
    echo "大于100"
else
    echo "小于100"
fi
root@ubuntu2404ser:~# bash test.sh
请输入数字: 11
数字小于100

#多条件分支
root@ubuntu2404ser:~# vim test.sh
#!/bin/bash
read -p "请输入您的分数: " num
if [[ $num -gt 90 ]];then
        echo "优秀"
elif [[ $num -gt 70 ]];then
        echo "很好"
elif [[ $num -gt 60 ]];then
        echo "合格"
elif [[ $num -eq 60 ]];then
        echo "你是不是在控分"
else
        echo "不及格"
fi

root@ubuntu2404ser:~# bash test.sh
请输入您的分数: 67
合格
root@ubuntu2404ser:~# bash test.sh
请输入您的分数: 91
优秀

2、case 多分支

# case 语法结构: case 变量 in 匹配模式) 执行逻辑 ;; esac , esac 是 case 反向结束标记。

# ;; 双分号:匹配分支结束分隔符,缺少会穿透执行下一个匹配分支。

# 核心优势:针对单一变量多固定值匹配,代码比多层 if-elif 更简洁,常用于菜单工具、脚本传参功能分发。

# 业务场景:运维工具箱菜单、启停脚本(start/stop/restart/status)、参数功能分发。
#标准语句
case 变量 in
模式1)
    命令
    ;;
模式2)
    命令
    ;;
*)
    #默认分支,相当于else
    命令
    ;;
esac


root@ubuntu2404ser:~# vim test.sh
root@ubuntu2404ser:~# cat test.sh
#!/bin/bash
read -p "请输入操作(start/stop/restart):" op
case $op in
        start)
                echo "运行中"
                ;;
        stop)
                echo "已停止"
                ;;
        reatart)
                echo "正在重启"
                ;;
        *)
                echo "请输入正确的参数: start/stop/restart"
                ;;
esac
root@ubuntu2404ser:~# bash test.sh
请输入操作(start/stop/restart):stop
已停止

root@ubuntu2404ser:~# bash test.sh
请输入操作(start/stop/restart):start
运行中

root@ubuntu2404ser:~# bash test.sh
请输入操作(start/stop/restart):reload
请输入正确的参数: start/stop/restart


root@ubuntu2404ser:~# cat > 'dxx.sh' << 'EOF'
#!/bin/bash
read -p "输入字母(A/B/C):" char
case $char in
a|A)
    echo "输入A"
    ;;
b|B)
    echo "输入B"
    ;;
c|C)
    echo "输入C"
    ;;
*)
    echo "其他字符"
    ;;
esac
EOF

root@ubuntu2404ser:~# bash dxx.sh
输入字母(A/B/C):a
输入A

root@ubuntu2404ser:~# bash dxx.sh
输入字母(A/B/C):c
输入C

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐