Shell 编程入门指南:从基础到实战2

目录

前言

字符串

[if...else 语句](#if...else 语句)

单支:

双支:

多支:

标准文件描述符(FD)

[重定向:> (覆盖) 与 >> (追加)](#重定向:> (覆盖) 与 >> (追加))

[重定向错误输出:2> / 2>>](#重定向错误输出:2> / 2>>)

[同时重定向 stdout 与 stderr](#同时重定向 stdout 与 stderr)

[POSIX 推荐(经常使用)](#POSIX 推荐(经常使用))

[将输出丢弃 /dev/null](#将输出丢弃 /dev/null)

总结


前言

在 Linux 世界里,"一切皆文件",而 Shell 则是我们与这些文件、进程、系统资源沟通的桥梁。判断字符串是否相等、检测端口是否被监听、验证文件权限、重定向输出与错误------这些看似琐碎的操作,恰恰构成了日常运维、自动化部署、故障排查的基石。本篇文章通过大量可直接复制运行的示例,把"字符串比较、文件测试、条件分支、重定向与文件描述符"这些高频知识点串成一条清晰的主线:

  • 从最简单的 [ "$a" = "$b" ] 开始,理解测试命令的"真/假"本质;

  • -f/-d/-r/-w/-x/-s/-e 等选项快速判断文件类型和权限;

  • 通过单分支、双分支、多分支的 if/elif/else 脚本,把零散的测试组合成有逻辑的业务流程;

  • 进一步用 >/>>/2>/2>>/&>/&>> 掌握标准输出(FD 1)与标准错误(FD 2)的重定向技巧;

  • 最终学会把"条件判断 + 重定向"综合运用到端口检测、网络探活、服务安装等真实场景。

字符串

-n 判断是否为非空

-z 判断是否为空

= 判断是否相等

!= 判断是否不相等

示例:判断两个是否相等

复制代码
[root@localhost shelldemo]# a=123
[root@localhost shelldemo]# b=123
[root@localhost shelldemo]# [ $a = $b ] && echo "两个字符串相等"
两个字符串相等
[root@localhost shelldemo]# [ $a != $b ] && echo "两个字符串不相等"

示例

shell脚本

复制代码
str="hello"
if [ -n "$str" ];then
        echo "字符串为非空"
else
        echo "字符串为空"
fi

运行

复制代码
[root@localhost shelldemo]# sh hello14.sh 
字符串为非空

文件
文件测试运算符 运算符号

测试选项 含义(为真时) 用法示例
-f 存在且是普通文件 [ -f 文件路径 ]
-d 存在且是目录 [ -d 目录路径 ]
-s 文件存在且大小不为 0 [ -s 文件路径 ]
-e 文件(或目录)存在 [ -e 文件路径 ]
-r 文件存在且当前用户可读 [ -r 文件路径 ]
-w 文件存在且当前用户可写 [ -w 文件路径 ]
-x 文件存在且当前用户可执行/可搜索 [ -x 文件路径 ]
复制代码
# 判断某一个目录是否可读可写
[root@localhost shelldemo]# [ -d /etc ] && [ -r /etc ] && echo "可读目录"
可读目录

# 判断该系统版本是否为英文版
[root@localhost shelldemo]# [ $LANG != "en.US" ] && echo "Not en.US"
Not en.US

# 判断当前用户是否小于等于5
[root@localhost shelldemo]# [ $(who|wc -l) -le 5 ] && echo "用户太少" 
用户太少
[root@localhost shelldemo]# [ $(who|wc -l) < 5 ] && echo "用户太少" 
用户太少

if...else 语句

单支

bash

复制代码
if [ 条件 ]; then
    命令
fi

示例

复制代码
# shell脚本
if [ -s /etc ];then
        echo "文件不为空"
fi

# 运行
[root@localhost shelldemo]# sh hello16.sh 
文件不为空

双支

bash

复制代码
if [ 条件 ]; then
    命令1
else
    命令2
fi

示例1

复制代码
# shell脚本
if [ $UID -eq 0 ]; then
        echo "当前用户是管理员"
else
        echo "当前用户不是管理员" 
fi

# 运行
[root@localhost shelldemo]# sh hello17.sh 
当前用户是管理员

示例2

复制代码
# shell脚本
num1=$1
num2=$2
if [ $num1 -gt $num2 ]; then
        echo "$num1大于$num2"
else
        echo "$num1小于$num2"
fi

# 运行
[root@localhost shelldemo]# sh hello18.sh 1234 456
1234大于456
[root@localhost shelldemo]# sh hello18.sh 765 1234567
765小于1234567

示例

复制代码
# shell脚本
if netstat -antulp|grep ":80" > /dev/null 2>&1; then
        echo "80端口运行"
else
        if [ $? -eq 0 ]; then
        echo "web网站服务已经运行"
        else
        echo "启动http服务"
        yum install -y httpd > /dev/null
        systemctl restart httpd
        fi
fi
# 注:/dev/null 2>&1 将错误日志传输,使得它往后面的if语句运行,yum云安装

# 运行
[root@localhost shelldemo]# sh hello19.sh 
启动http服务
file:///mnt/repodata/repomd.xml: [Errno 14] curl#37 - "Couldn't open file /mnt/repodata/repomd.xml"
正在尝试其它镜像。

示例

复制代码
# shell脚本
ip=$1
ping -c 2 -i 0.2 -W 3 $ip &> /dev/null
#-c 次数  -i ping一次多少秒 -W 反馈结果的时间
if [ $? -eq 0 ]; then
        echo "$ip is up"
else
        echo "$ip is down"
fi
                                

# 运行
[root@localhost shelldemo]# sh hello20.sh 192.168.10.106
192.168.10.106 is up
[root@localhost shelldemo]# sh hello20.sh 192.168.10.105
192.168.10.105 is down

示例:判断httpd是否安装

复制代码
# shell脚本
rpm -q httpd >rpm.txt 2>&1
if [ $? -eq 0 ]; then
        echo "安装httpd"
else
        echo "没安装httpd"
fi

# 测试
[root@zardcopy Y]# sh dome1.sh
安装httpd

示例:需求:检查用户是否存在 如果不存在就创建新用户,并且设置初始密码为"123456"

复制代码
# shell脚本
read -p "请输入当前用户名:" username
cat /etc/passwd|grep $username
if [ $? -eq 0 ]; then
        echo "用户已创建"
else
        echo "用户没有创建"
        useradd $username
        echo "123" | passwd --stdin $username
fi

# 测试
[root@localhost shelldemo]# sh dome7.sh 
请输入当前用户名:test4
用户没有创建
更改用户 test4 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@localhost shelldemo]# su - test4
[test4@localhost ~]$ su - test4
密码:
上一次登录:六 8月 30 09:41:46 CST 2025pts/2 上
[test4@localhost ~]$ su - root
密码:
上一次登录:六 8月 30 09:26:23 CST 2025从 192.168.10.90pts/2 上

多支

复制代码
if [ 条件1 ]; then
    命令1
elif [ 条件2 ]; then
    命令2
...
else
    默认命令
fi
示例:判断分数等级

bash

复制代码
#!/bin/bash
score=$1
if [ $score -ge 90 ]; then
    echo "优秀"
elif [ $score -ge 80 ]; then
    echo "良好"
elif [ $score -ge 60 ]; then
    echo "及格"
else
    echo "不及格"
fi

# 运行
[root@localhost shelldemo]# sh hello10.sh 98
优秀
示例:写一个脚本,判断文件类型 d f b
复制代码
# shell脚本
read -p "请输入路径:" name
if [ -d $name ]; then
        echo "这是一个文件夹"
elif [ -f $name ]; then
        echo "这是一个文件"
elif [ -b $name ]; then
        echo "这是一个设备文件"
else
        echo "无法判断"
fi

# 输出结果
[root@localhost shelldemo]# sh hello21.sh 
请输入路径:/root
这是一个文件夹
[root@localhost shelldemo]# sh hello21.sh 
请输入路径:/root/shelldemo/hello21.sh
这是一个文件

示例:

复制代码
# shell脚本
# 用date命令记录当前的小时
a=$(date +%H)
# if判断
if [ $a -ge 6 -a $a -lt 11 ]; then
	echo "现在是上午$a点"
elif [ $a -ge 11 -a $a -lt 13 ]; then
	echo "现在是中午$a点"
elif [ $a -ge 13 -a $a -lt 18 ]; then
	echo "现在是下午$a点"
elif [ $a -ge 18 -a $a -lt 24 ]; then
	echo "现在是晚上$a点"
else 
	echo "现在是凌晨$a点"
fi

# 测试
[root@localhost shelldemo]# sh dome21.sh 
现在是上午08点
[root@localhost shelldemo]# date -s "2025-08-30 12:00:00"
2025年 08月 30日 星期六 12:00:00 CST
[root@localhost shelldemo]# sh dome21.sh 
现在是中午12点
[root@localhost shelldemo]# date -s "2025-08-30 16:00:00"
2025年 08月 30日 星期六 16:00:00 CST
[root@localhost shelldemo]# sh dome21.sh 
现在是下午16点

标准文件描述符(FD

0 = stdin (标准输入)
1 = stdout (标准输出)
2 = stderr (标准错误)
示例(分别演示 stdout/stderr ):

复制代码
[root@localhost shelldemo]# echo "out"
out   # 到 stdout
[root@localhost shelldemo]# echo "err" >&2
err   # 到stderr

重定向:> (覆盖) 与 >> (追加)

> 把 stdout 写到文件(覆盖原内容)
>> 把 stdout 追加到文件末尾

复制代码
[root@localhost shelldemo]# echo "first" > file.txt
[root@localhost shelldemo]# echo "second" > file.txt
[root@localhost shelldemo]# cat file.txt              #覆盖
second
[root@localhost shelldemo]# echo "third" >> file.txt
[root@localhost shelldemo]# cat file.txt              #追加
second
third

**重定向错误输出:2>/**2>>

复制代码
[root@localhost shelldemo]# ls /no/such/path 2>err.txt   #重覆盖
[root@localhost shelldemo]# cat err.txt                 
ls: 无法访问/no/such/path: 没有那个文件或目录
[root@localhost shelldemo]# ls /no/same/file 2>>err.txt   #追加
[root@localhost shelldemo]# cat err.txt
ls: 无法访问/no/such/path: 没有那个文件或目录
ls: 无法访问/no/same/file: 没有那个文件或目录

同时重定向stdout与****stderr

有几种常用写法(要注意兼容性与顺序):

POSIX****推荐(经常使用)

复制代码
command >out.txt 2>&1

含义:先把 stdout 重定向到 out.txt ,再把 stderr(2)重定向到当前 stdout(1)指向的位置(也就
是 out.txt )。结果: stdout 和 stderr 都写入 out.txt 。

复制代码
# 先传正确,再传错误
[root@localhost shelldemo]# bash -c 'echo out; echo err >&2' >both.txt 2>&1
[root@localhost shelldemo]# cat both.txt
out
err

# 仅仅把错误的传过去
[root@localhost shelldemo]# bash -c 'echo out; echo err >&2' 2>&1 >both.txt
err

将输出丢弃/dev/null

含义 :把不想要的输出重定向到 /dev/null (黑洞)。
示例:只保留 stderr ,丢弃 stdout :

复制代码
$ some_command > /dev/null

丢弃 stderr :

复制代码
$ some_command 2> /dev/null

同时丢弃两者:

复制代码
$ some_command > /dev/null 2>&1
# 或(bash):
$ some_command &> /dev/null

总结

  1. 判断的本质:任何测试命令([ ][[ ]](( ))、命令本身)都会返回"退出状态码"------0 为真,非 0 为假;脚本只需根据这个状态码决定下一步动作。

  2. 文件与字符串测试:记住常用选项(-f/-d/-e/-r/-w/-x/-s/-n/-z),就能在一行内完成"存在性、类型、权限、空值"四大类检查。

  3. 条件结构:

    • 单分支 if ... then ... fi ------ 满足就执行;

    • 双分支 if ... then ... else ... fi ------ 二选一;

    • 多分支 if ... elif ... else ... fi ------ 多选一。

  4. 重定向:

    • > 覆盖、>> 追加、2> 定向错误、&> 合并全部;

    • /dev/null 是"黑洞",任何不想保留的输出都可以丢进去;

    • 顺序决定结果:>file 2>&1 合并输出与错误到 file;2>&1 >file 则只把错误合并到原 stdout。

  5. 实战套路:

    • 端口检测:netstat -antulp | grep -q ":80"

    • 网络探活:ping -c 2 -W 3 $ip &>/dev/null && echo up || echo down

    • 服务安装:先端口检测 → 不存在就 yum/dnf install -y httpd && systemctl enable --now httpd

把这些基本积木拼接起来,你就能写出既健壮又易维护的自动化脚本,真正做到"让 Shell 替你搬砖,而你专注思考"。

相关推荐
Larcher27 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐40 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭1 小时前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信1 小时前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程