Linux shell编程是Linux系统管理、自动化运维及日常任务处理的核心技能,通过编写shell脚本(以.sh为扩展名),用户可以将一系列命令组合成可执行的程序,实现重复任务的自动化、复杂操作的简化以及系统状态的监控,在shell终端(通常提示符为$或#,普通用户为$,root用户为#)下进行编程,主要依赖于bash(Bourne Again Shell)、zsh等解释器,下面从基础到进阶详细介绍shell编程的关键内容。
shell脚本基础结构与执行
shell脚本以文本形式保存,第一行必须指定解释器,称为shebang,例如#!/bin/bash
表示使用bash解释器执行,脚本编写完成后,需通过chmod +x script.sh
添加执行权限,再通过./script.sh
(当前目录)或/path/to/script.sh
(绝对路径)执行,也可使用bash script.sh
直接调用解释器执行(无需执行权限)。
脚本基本结构包括:
- shebang行(指定解释器)
- 注释(以#开头,解释代码逻辑)
- 变量定义与使用
- 命令序列(可包含条件判断、循环、函数等)
#!/bin/bash # 这是一个简单的shell脚本 name="Linux" echo "Hello, $name!" # 输出Hello, Linux!
变量与参数
自定义变量
变量定义时无需声明类型,直接赋值即可,例如count=10
(等号两侧无空格),使用时需加前缀(如echo $count
),变量名需以字母或下划线开头,避免使用保留字(如if、for)。
特殊变量
shell预定义了一些特殊变量,用于获取脚本执行时的参数或状态,如下表:
变量名 | 含义 | 示例(脚本./test.sh arg1 arg2 ) |
---|---|---|
$0 | 脚本名称 | echo $0 → 输出./test.sh |
$1~$9 | 位置参数(第1~9个参数) | echo $1 → 输出arg1 |
${10}+ | 位置参数(第10个及以上) | echo ${10} → 输出第10个参数 |
参数个数 | echo $# → 输出2 |
|
所有参数(单个字符串) | echo $* → arg1 arg2 |
|
所有参数(独立字符串) | for i in "$@"; do echo $i; done → 逐行输出arg1、arg2 |
|
上一条命令的退出状态 | echo $? → 0表示成功,非0表示失败 |
|
当前进程ID | echo $$ → 输出脚本进程的PID |
只读变量与删除变量
使用readonly
定义只读变量(不可修改),例如readonly flag=1
;使用unset
删除变量,例如unset count
(只读变量不可删除)。
流程控制
条件判断:if-else
条件判断通过test
命令或[ ]
实现([ ]
内部与test等效,需注意与命令间有空格),常用判断条件包括:
判断类型 | 选项示例 | 含义 |
---|---|---|
文件测试 | -f file | file存在且为普通文件 |
-d dir | dir存在且为目录 | |
-r file | file可读 | |
-eq(数值) | 等于 | |
-ne(数值) | 不等于 | |
字符串 | 等于 | |
不等于 | ||
-z str | str长度为0 | |
-n str | str长度不为0 |
if-else结构示例:
#!/bin/bash score=85 if [ $score -ge 90 ]; then echo "优秀" elif [ $score -ge 60 ]; then echo "及格" else echo "不及格" fi
循环结构
(1)for循环
遍历列表或文件,示例:
# 遍历列表 for i in "apple" "banana" "orange"; do echo "水果: $i" done # 遍历当前目录下的.sh文件 for file in *.sh; do echo "脚本文件: $file" done
(2)while循环
根据条件循环,示例:
#!/bin/bash count=1 while [ $count -le 5 ]; do echo "计数: $count" ((count++)) # 变量自增(等同于count=$[$count+1]) done
(3)until循环
条件为假时循环,与while相反:
until [ $count -gt 5 ]; do echo "计数: $count" ((count++)) done
case语句
多分支选择,适合匹配多个条件:
#!/bin/bash read -p "请输入一个字符: " char case $char in [a-z]) echo "小写字母" ;; [A-Z]) echo "大写字母" ;; [0-9]) echo "数字" ;; *) echo "其他字符" ;; esac
函数
函数将代码模块化,支持参数传递和返回值,定义格式为function_name() { commands; }
,调用时直接写函数名。
函数定义与调用
#!/bin/bash # 定义函数 add() { local sum=$(($1 + $2)) # local声明局部变量(仅函数内有效) echo "和为: $sum" return $sum # 返回值(0-255) } # 调用函数 add 3 5 # 输出“和为: 8” echo "返回值: $?" # 输出返回值8
函数参数
函数内通过$1
、$2
等获取参数,参数个数通过获取,与脚本参数类似。
常用命令与工具
shell编程离不开Linux命令的组合使用,以下是核心工具:
命令 | 作用 | 示例 |
---|---|---|
grep | 文本过滤 | grep "error" log.txt → 查找包含error的行 |
sed | 流编辑器(文本替换/删除) | sed 's/old/new/g' file → 全局替换old为new |
awk | 文本分析(按列处理) | awk '{print $1, $3}' file → 输出第1、3列 |
cut | 截取列 | cut -d: -f1 /etc/passwd → 按冒号分隔取第1列 |
sort | 排序 | sort -n numbers.txt → 按数值排序 |
uniq | 去重 | sort file | uniq → 先排序后去重 |
find | 文件查找 | find / -name "*.log" -type f → 查找所有.log文件 |
xargs | 将输入转换为命令参数 | echo "a b c" | xargs -n 1 echo → 逐行输出a、b、c |
调试与错误处理
调试选项
使用bash -x script.sh
执行脚本,会打印每条命令的执行结果,适合排查逻辑错误。
#!/bin/bash # 调试模式执行 for i in {1..3}; do echo "当前i: $i" done
执行bash -x test.sh
,输出会显示+ echo '当前i: 1'
等调试信息。
错误处理
set -e
:脚本中任何命令返回非0状态时立即退出(避免错误累积)。set -u
:使用未定义变量时报错(避免变量名拼写错误)。set -o pipefail
:管道中任何命令失败时,整个管道返回非0状态(默认仅最后一个命令的状态生效)。trap
:捕获信号(如Ctrl+C)或错误,执行自定义操作:#!/bin/bash trap 'echo "脚本被中断或出错!"' ERR INT # 捕获错误(ERR)和中断信号(INT) rm /nonexistent/file # 此命令会出错,触发trap
实践建议
- 从简单脚本开始:先编写文件备份、日志清理等基础脚本,逐步过渡到复杂逻辑。
- 善用注释:关键逻辑处添加注释,方便后续维护。
- 测试与验证:使用不同数据测试脚本边界条件(如空输入、超大文件)。
- 避免危险命令:谨慎使用
rm -rf
、> /dev/sda
等命令,执行前务必确认路径正确。
相关问答FAQs
Q1: shell脚本和Python脚本在Linux自动化中如何选择?
A: 选择取决于场景:若任务涉及大量文本处理、系统命令调用(如批量修改文件权限、监控进程状态),shell脚本更轻量高效,直接调用系统命令,无需额外依赖;若任务涉及复杂逻辑(如数学计算、数据处理)、跨平台需求或需要第三方库(如requests、pandas),Python更合适,语法更易读,且拥有丰富的生态。“简单命令组合用shell,复杂逻辑用Python”。
Q2: 如何让shell脚本在系统启动时自动执行?
A: 方法取决于Linux发行版和需求:
-
/etc/rc.local:在较旧发行版(如CentOS 7之前)中,将脚本路径添加到
/etc/rc.local
文件(需确保文件有执行权限chmod +x /etc/rc.local
),并在文件开头添加#!/bin/bash
。 -
systemd服务:现代发行版(如Ubuntu 18.04+、CentOS 7+)推荐使用systemd,创建服务文件(如
/etc/systemd/system/myscript.service
如下:[Unit] Description=My Custom Script After=network.target # 网络启动后执行 [Service] Type=oneshot ExecStart=/path/to/your/script.sh User=root [Install] WantedBy=multi-user.target
然后执行
systemctl enable --now myscript.service
即可开机自启。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/15290.html