学习Shell编程是一项非常有用的技能,特别是在管理和自动化Linux/Unix系统方面。以下是一个Shell编程的入门指南:
1. 基本概念
- Shell:Shell是操作系统的命令解释器,允许用户与操作系统进行交互。常见的Shell有Bash(Bourne Again Shell)、Zsh、Ksh等。
- 脚本:Shell脚本是包含Shell命令的文本文件,可以自动化执行一系列操作。
2. 环境设置
- 安装Shell:大多数Linux系统默认使用Bash作为Shell,可以通过终端进行验证:
-
echo $SHELL
- 编辑器:可以使用任何文本编辑器来编写Shell脚本,如Vim、Nano、VSCode等。
-
3. 编写第一个Shell脚本
- 创建脚本文件:
-
添加可执行权限:touch myscript.sh
-
编辑脚本文件:chmod +x myscript.sh
-
运行脚本:#!/bin/bash echo "Hello, World!"
-
./myscript.sh
4. 基本语法
- 变量:
-
用户输入:myvar="Hello" echo $myvar
-
条件语句:echo "Enter your name:" read name echo "Hello, $name!"
-
循环:if ["$name" == "Alice"]; then echo "Welcome, Alice!" else echo "Hello, $name!" fi
-
for i in {1..5} do echo "Looping ... number $i" done
5. 常用命令
- 文件操作:
cp
、mv
、rm
、mkdir
- 文本处理:
cat
、grep
、awk
、sed
- 系统信息:
uname
、df
、top
、ps
6. 函数
- 定义和调用函数:
-
myfunc() { echo "This is a function" } myfunc
7. 调试脚本
- 打印调试信息:
-
set -x # Your script here set +x
检查语法错误:
-
bash -n myscript.sh
9. 文件操作和文本处理
9.1 文件操作
- 创建文件:
-
touch filename.txt
复制文件:
-
cp source.txt destination.txt
移动/重命名文件:
-
mv oldname.txt newname.txt
删除文件:
-
rm filename.txt
创建目录:
-
mkdir dirname
9.2 文本处理
- 显示文件内容:
-
cat filename.txt
查找文本:
-
grep "search_term" filename.txt
按行或字段分割文本:
-
awk '{print $1}' filename.txt
编辑文本:
-
sed 's/old/new/g' filename.txt
10. 控制流
10.1 条件语句
-
if 语句:
-
if [ condition ]; then # commands elif [ condition ]; then # commands else # commands fi
-
条件运算符:
-eq
:等于-ne
:不等于-lt
:小于-le
:小于或等于-gt
:大于-ge
:大于或等于
-
for 循环:
-
10.2 循环
-
for var in list do # commands done
while 循环:
-
while [ condition ] do # commands done
until 循环:
-
until [ condition ] do # commands done
11. 函数和脚本参数
11.1 函数
- 定义函数:
-
myfunc() { # commands }
调用函数:
-
myfunc
11.2 脚本参数
-
访问参数:
-
echo "First parameter: $1" echo "Second parameter: $2"
参数计数:
-
echo "Number of parameters: $#"
所有参数:
-
echo "All parameters: $@"
12. 高级文本处理
12.1 awk
-
基本使用:
-
awk '{print $1}' filename.txt
条件处理:
-
awk '$1 ~ /pattern/ {print $2}' filename.txt
12.2 sed
-
替换文本:
-
sed 's/old/new/g' filename.txt
删除行:
-
sed '/pattern/d' filename.txt
13. 实用工具和技巧
-
定时任务:
-
crontab -e # 添加如下行,每天凌晨3点执行脚本 0 3 * * * /path/to/script.sh
脚本调试:
-
bash -x script.sh
命令替换:
-
result=$(command) echo $result
子shell:
-
(command1; command2)
14. 数组和关联数组
14.1 数组
-
定义数组:
-
my_array=(value1 value2 value3)
访问数组元素:
-
echo ${my_array[0]} # 输出value1
获取数组长度:
-
echo ${#my_array[@]} # 输出数组长度
遍历数组:
-
for element in "${my_array[@]}" do echo $element done
14.2 关联数组(仅限Bash 4.0及以上)
-
定义关联数组:
-
declare -A my_assoc_array my_assoc_array[key1]=value1 my_assoc_array[key2]=value2
访问关联数组元素:
-
echo ${my_assoc_array[key1]} #输出valuel1
获取关联数组键列表:
-
echo ${!my_assoc_array[@]} #输出key1 key2
15. Shell 内置命令和特殊变量
15.1 内置命令
echo
:输出文本read
:从标准输入读取输入exit
:退出脚本并返回状态码cd
:改变当前目录pwd
:显示当前工作目录export
:设置环境变量
15.2 特殊变量
$?
:上一条命令的退出状态$$
:当前脚本的进程ID$0
:当前脚本的名称$@
和$*
:所有参数
16. 错误处理和调试技巧
16.1 错误处理
-
使用
set
命令: -
set -e #遇到错误时退出脚本 set -u #使用未定义变量报错
捕获错误
-
command || {echo "Command failed"; exit 1;}
16.2 调试技巧
-
使用
set
命令:
set -x #打开调试模式
set +x #关闭调试模式
检查语法错误
bash -n script.sh
17. 与其他命令结合
17.1 管道和重定向
-
管道:
-
command1 | command2 #command1的输出作为command2的输入
重定向:
-
command > output.txt #将输出重定向到文件 command < input.txt #将文件读取输入 command >> output.txt #将输出追加到文件
错误重定向:
-
command 2> error.log #将错误输出重定向到文件
17.2 后台运行和作业控制
-
后台运行:
-
command &
作业控制
-
jobs #列出所有作业 fg %1 #将作业1放到前台 bg %1 #在后台运行作业1 kill %1 #终止作业1
18. 实战示例
18.1 自动备份脚本
-
#!/bin/bash #目录和文件 src_dir = "/path/to/source" dest_dir="/path/to/destination" backup_file="backup_${data + %Y%m%d}.tar.gz" #创建备份 tar -czf $dest_dir/$backup_file $src_dir #检查备份是否成功 if [$? -eq 0]; then echo "Backup successful: $backup_file" else echo "Backup failed" exit 1 fi
18.2 系统监控脚本
-
31/bin/bash #获取系统信息 hostname = $(hostname) uptime = $(uptime -p) disk_usage = $(df -h / | grep / | awk '{ print $5 }') #输出系统信息 echo "Hostname: $hostname" echo "Uptime: $uptime" echo "Disk Usage: $disk_usage"
19. 正则表达式和文本处理
19.1 基本正则表达式
-
字符匹配:
.
:匹配任意单个字符[]
:匹配括号内的任意字符[^]
:匹配不在括号内的任意字符
-
重复匹配:
*
:匹配前面的字符0次或多次+
:匹配前面的字符1次或多次?
:匹配前面的字符0次或1次{n}
:匹配前面的字符n次{n,}
:匹配前面的字符至少n次{n,m}
:匹配前面的字符n到m次
-
位置匹配:
^
:匹配行的开始$
:匹配行的结束
-
19.2 grep命令
-
基本使用:
-
grep "pattern" filename #在文件filename中查找pattern
忽略大小
-
grep -i "pattern" filename
递归搜索
-
grep -r "pattern" directory
显示行号:
-
grep -n "pattern" filename
19.3 sed命令
-
基本替换:
-
sed ‘s/old/new/g’ filename
多重编辑:
-
sed -e 's/old1/new1/g' -e 's/old2/new2/g' filename
行的插入和删除:
-
sed '2i\This is inserted line' filename #在第二行后插入 sed '2d' filename #删除第二行
19.4 awk命令
-
基本使用:
-
awk '{ print $1 }' filename
使用条件
-
awk '$1 ~ /pattern/ { print $2 }' filename
计算和统计
-
awk '{sum+=$1} END {print sum}' filename
20. 高级脚本控制
20.1 捕获信号
-
捕获信号并处理:
-
trap "echo 'Interrupt signal received'; exit" SIGINT while true do echo "Running..." sleep 1 done
-
常见信号:
SIGINT
:终止信号(Ctrl+C)SIGTERM
:终止信号SIGHUP
:挂起信号SIGKILL
:强制终止信号
-
启动子进程:
-
20.2 子进程管理
-
(command1; command2) &
等待子进程完成
-
wait
21. 交互式脚本和用户输入
21.1 基本用户输入
-
读取输入:
-
echo "Enter your name:" read name echo "Hello, $name!"
读取密码输入:
-
read -s -p "Enter your password: " password echo
21.2 高级用户输入
- 菜单和选项:
-
PS3="Choose an option: " options=("Option 1" "Option 2" "Option 3" "Quit") select opt in "${options[@]}" do case $opt in "Option 1") echo "You chose option 1" ;; "Option 2") echo "You chose option 2" ;; "Option 3") echo "You chose option 3" ;; "Quit") break ;; *) echo "Invalid option" ;; esac done
22. 实用脚本示例
22.1 日志轮转脚本
-
#!/bin/bash log_dir="/var/log/myapp" archive_dir="/var/log/myapp/archive" mkdir -p $archive_dir for logfile in $log_dir/*.log do base=$(basename $logfile) mv $logfile $archive_dir/$base.$(date +%Y%m%d) touch $logfile done # 删除30天前的日志 find $archive_dir -type f -mtime +30 -exec rm {} \;
22.2 系统健康检查脚本
-
#!/bin/bash echo "System Health Check" # CPU使用率 cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1"%"}') echo "CPU Usage: $cpu_usage" # 内存使用情况 mem_usage=$(free -m | awk 'NR==2{printf "Memory Usage: %.2f%%\n", $3*100/$2 }') echo $mem_usage # 磁盘使用情况 disk_usage=$(df -h | grep '^/dev/' | awk '{ print $5 " " $1 }') echo "Disk Usage:" echo "$disk_usage"