shell练习题
第一部分:基础概念与变量
1. Shell特殊位置参数变量的含义
| 变量 | 含义 |
|---|---|
$0 | 脚本本身的名称(如果以路径执行,则包含路径) |
$n | 传递给脚本的第 n 个参数(n=1..9,${10} 表示第10个) |
$# | 传递给脚本的参数总个数 |
$* | 所有参数作为一个整体字符串("$1 $2 ...") |
$@ | 所有参数作为独立字符串("$1" "$2" ...),推荐使用 |
$? | 上一条命令的退出状态码,0 表示成功,非0 失败 |
$$ | 当前 shell 进程的 PID |
$! | 后台运行的最后一个进程的 PID |
$_ | 上一个命令的最后一个参数 |
2. 如何定义环境变量
使用 export 命令将普通变量提升为环境变量(全局变量),例如:
export MYENV="hello"
若希望永久生效,可将上述命令写入 ~/.bashrc 或 /etc/profile,然后执行 source ~/.bashrc。
3. 变量定义时,不加引号、单引号、双引号、反引号的区别与用法
| 写法 | 说明 | 示例 |
|---|---|---|
| 不加引号 | 值不能包含空格或特殊字符(如 &、;),会进行变量替换和命令替换 | name=oldboy |
单引号 ' ' | 所见即所得,不解析变量和命令,所有字符均为字面量 | name='$a' → 值 $a |
双引号 " " | 解析变量和命令替换,支持转义(如 \$) | name="$a" → 值等于变量 a 的值 |
反引号 ` ` | 命令替换,执行里面的命令,将输出作为值(已过时,推荐 $()) | dir=`pwd` |
用法建议:
- 普通无特殊字符的字符串:不加引号
- 需要保留空格或特殊字符的字符串:加双引号
- 不希望解析变量的内容:加单引号
- 命令替换:优先使用
$(),例如dir=$(pwd)
4. 特殊变量扩展的意义
| 表达式 | 含义 |
|---|---|
${oldboy} | 取变量 oldboy 的值(与 $oldboy 相同,但花括号可界定变量名边界) |
${#oldboy} | 取变量 oldboy 的字符串长度 |
${url#*.} | 从 url 变量的值开头删除最短匹配 *. 的部分(非贪婪,删除第一个点及其之前的内容) |
${url##*.} | 从开头删除最长匹配 *. 的部分(贪婪,删除最后一个点及其之前的内容) |
${url%.*} | 从末尾删除最短匹配 .* 的部分(非贪婪,删除最后一个点及其之后的内容) |
${url%%.*} | 从末尾删除最长匹配 .* 的部分(贪婪,删除第一个点及其之后的内容) |
举例:url=www.sina.com
${url#*.}→sina.com${url##*.}→com${url%.*}→www.sina${url%%.*}→www
5. 数值的整数和小数运算有哪几种方式
| 类型 | 方式 | 示例 |
|---|---|---|
| 整数运算 | expr | expr 1 + 1 |
$[] | echo $[1+1] | |
$(()) | echo $((1+1)) | |
let | let a=1+1 | |
| 整数+小数运算 | bc 命令 | echo scale=2; 10/3" | bc |
awk | awk 'BEGIN{print 10/3}' |
6. 条件测试的含义
| 表达式 | 含义 |
|---|---|
[ -e dir|file ] | 测试文件或目录是否存在(exist) |
[ -d dir ] | 测试是否为目录(directory) |
[ -f file ] | 测试是否为普通文件(file) |
[ -r file ] | 测试文件是否可读(read) |
[ -x file ] | 测试文件是否可执行(executable) |
[ -w file ] | 测试文件是否可写(write) |
7. 字符串测试操作符
-n:字符串长度不为0则为真-z:字符串长度为0则为真
8. 整数比较符
-eq:等于-ne:不等于-gt:大于-ge:大于等于-lt:小于-le:小于等于
第二部分:简单编程题
9. 判断文件不存在则创建
[ -f /tmp/oldboy.txt ] || touch /tmp/oldboy.txt
10. 查看磁盘使用率,超过80%输出到/var/log/disk.err
#!/bin/bash
usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ $usage -gt 80 ]; then
echo "$(date) 磁盘使用率 ${usage}% 超过80%" >> /var/log/disk.err
fi
11. 批量创建10个用户,密码123,判断输入为空和数字
#!/bin/bash
read -p "请输入用户名前缀: " prefix
read -p "请输入用户个数: " num
if [ -z "$prefix" ]; then
echo "前缀不能为空"
exit 1
fi
if ! [[ "$num" =~ ^[0-9]+$ ]]; then
echo "个数必须是数字"
exit 1
fi
for i in $(seq 1 $num); do
username="${prefix}${i}"
useradd $username 2>/dev/null
echo "123" | passwd --stdin $username &>/dev/null
echo "用户 $username 创建成功,密码123"
done
12. 猜数字游戏(1-100),统计次数
#!/bin/bash
target=$((RANDOM % 100 + 1))
count=0
while true; do
read -p "请输入1-100之间的数字: " guess
if ! [[ "$guess" =~ ^[0-9]+$ ]] || [ $guess -lt 1 ] || [ $guess -gt 100 ]; then
echo "输入无效,请输入1-100的整数"
continue
fi
((count++))
if [ $guess -gt $target ]; then
echo "大了"
elif [ $guess -lt $target ]; then
echo "小了"
else
echo "恭喜你猜对了!共猜了 $count 次"
break
fi
done
13. 菜单循环+case
#!/bin/bash
while true; do
cat << EOF
h 显示命令帮助
f 显示登陆信息
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
read -p "请输入选项: " opt
case $opt in
h) echo "帮助信息:可选 h,f,d,m,u,q" ;;
f) who ;;
d) df -h ;;
m) free -h ;;
u) uptime ;;
q) exit 0 ;;
*) echo "无效选项" ;;
esac
done
14. nginx 启动脚本(case语句)
#!/bin/bash
nginx="/usr/sbin/nginx"
case $1 in
start)
$nginx
;;
stop)
$nginx -s stop
;;
reload)
$nginx -s reload
;;
restart)
$nginx -s stop && sleep 1 && $nginx
;;
status)
if pgrep nginx >/dev/null; then
echo "nginx is running"
else
echo "nginx is stopped"
fi
;;
*)
echo "Usage: $0 {start|stop|reload|restart|status}"
exit 1
esac
15. 探测 10.0.0.1-254 存活主机,输出到 ip.txt
#!/bin/bash
> ip.txt
for i in {1..254}; do
(ping -c1 -W1 10.0.0.$i &>/dev/null && echo 10.0.0.$i) &
done >> ip.txt
wait
16. 统计句子中字母数不大于6的单词
句子:I am oldboy teacher welcome to oldboy training class.
echo "I am oldboy teacher welcome to oldboy training class." | xargs -n1 | awk 'length<=6'
17. 计算从1加到100之和
# 方法1:for循环
sum=0; for i in {1..100}; do sum=$((sum+i)); done; echo $sum
# 方法2:公式
echo $((100 * 101 / 2))
18. while循环实现1加到100
#!/bin/bash
sum=0; i=1
while [ $i -le 100 ]; do
sum=$((sum+i))
((i++))
done
echo $sum
19. 批量创建文件并改名(/oldboy目录,随机字母+oldboy,改为oldgirl)
#!/bin/bash
mkdir -p /oldboy
for i in {1..10}; do
rand=$(cat /dev/urandom | tr -dc 'a-z' | head -c 10)
touch "/oldboy/${rand}_oldboy.html"
done
cd /oldboy
for file in *_oldboy.html; do
mv "$file" "${file//oldboy/oldgirl}"
done
20. 输入两个整数计算加减乘除求余
#!/bin/bash
if [ $# -ne 2 ]; then echo "Usage: $0 num1 num2"; exit 1; fi
echo "加法: $(( $1 + $2 ))"
echo "减法: $(( $1 - $2 ))"
echo "乘法: $(( $1 * $2 ))"
echo "除法: $(( $1 / $2 ))"
echo "求余: $(( $1 % $2 ))"
21. sed删除前5行含字母的行,删除6-10行所有字母
sed '1,5{/[a-zA-Z]/d};6,10{s/[a-zA-Z]//g}' input.txt > output.txt
22. 统计自定义用户(普通用户)个数
awk -F: '$3>=1000 && $3<65534 {c++} END {print c+0}' /etc/passwd
23. 统计最常用的10个命令(基于历史文件)
cat ~/.bash_history | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
24. 计算100以内能被3整除的数之和
sum=0; for i in {1..100}; do [ $((i%3)) -eq 0 ] && sum=$((sum+i)); done; echo $sum
25. 将条件表达式 [ -f /etc/hosts ] && echo ! 改写为if语句
if [ -f /etc/hosts ]; then echo "!"; fi
26. 按单词频率降序排序 / 按字母频率降序排序
文本:the squid project provides a number of resources to assist users design,implement and support squid installations. Please browse the documentation and support sections for more infomation
# 单词频率
echo "..." | tr ' ' '\n' | sort | uniq -c | sort -rn
# 字母频率
echo "..." | grep -o '[a-zA-Z]' | sort | uniq -c | sort -rn
27. 杀死所有名为test.sh的进程
pkill -f test.sh
# 或
ps aux | grep test.sh | grep -v grep | awk '{print $2}' | xargs kill -9
28. 打印文本文档中只有一个数字的行
grep -x '[0-9]\+' input.txt
29. 通过curl状态码判断网站是否正常
status=$(curl -o /dev/null -s -w "%{http_code}" http://example.com)
[ "$status" -eq 200 ] && echo "正常" || echo "异常,状态码 $status"
30. 抓阄程序(输入英文名,生成01-99不重复随机数,数字越大越优先)
#!/bin/bash
> record.txt
while true; do
read -p "请输入英文名字(输入 quit 退出): " name
[ "$name" = "quit" ] && break
while true; do
num=$((RANDOM % 99 + 1))
num=$(printf "%02d" $num)
if ! grep -q "^$num$" record.txt; then
echo "$num" >> record.txt
echo "$name $num" | tee -a result.txt
break
fi
done
done
sort -rnk2 result.txt
第三部分:数组与高级控制
31. 普通数组和关联数组定义
普通数组:
arr=(a b c) # 方式1
arr[0]=a; arr[1]=b # 方式2
关联数组:
declare -A assoc
assoc[name]="tom"; assoc[age]=18 # 方式1
declare -A assoc=([name]="tom" [age]=18) # 方式2
32. 查看数组索引和元素个数
echo ${!array[@]} # 索引
echo ${#array[@]} # 元素个数
33. 将数组 array=(1 2 3 4 5 6) 中的3替换为C
array=(1 2 3 4 5 6); array[2]=C; echo ${array[@]}
34. 打印数组每个元素(每行一个)
array=(1 2 3 4 5 6)
for i in "${array[@]}"; do echo $i; done
35. 使用数组判断句子中字母数大于6的单词
句子:I am oldboy teacher welcome to training class
str="I am oldboy teacher welcome to training class"
words=($str)
for w in "${words[@]}"; do
[ ${#w} -gt 6 ] && echo $w
done
36. 统计Nginx日志中每个IP的访问量
awk '{print $1}' access.log | sort | uniq -c | sort -rn
37. 统计Nginx日志中访问最多的10个IP的流量总和
awk '{ip=$1; bytes=$10} {sum[ip]+=bytes} END {for(ip in sum) print sum[ip], ip}' access.log | sort -rn | head -10 | awk '{total+=$1} END {print "总流量:", total}'
38. 计算所有进程占用内存大小的和(KB)
ps -eo rss --no-headers | awk '{sum+=$1} END {print sum " KB"}'
39. 按照时间生成文件(如2018-05-22.log)写入磁盘状态
logfile=$(date +%Y-%m-%d).log; df -h > "$logfile"
40. 在/backup下创建10个.txt文件,批量修改后缀为.bak,打包,还原
#!/bin/bash
mkdir -p /backup
for i in {1..10}; do touch "/backup/file${i}.txt"; done
cd /backup
for f in *.txt; do mv "$f" "${f}.bak"; done
tar -czf 123.tar.gz *.bak
for f in *.bak; do mv "$f" "${f%.bak}"; done
第四部分:流程控制(break/continue/exit/return)
| 命令 | 含义 |
|---|---|
exit | 退出当前 shell 或脚本,可返回状态码 |
break | 跳出当前循环(for、while、until) |
continue | 跳过本次循环剩余部分,进入下一次循环迭代 |
return | 用于函数,返回函数执行状态,退出函数体 |
第五部分:补充综合练习
41. 生成随机数相加直到大于1000,输出总和及最后一个数能否被3整除
#!/bin/bash
sum=0; last=0
while [ $sum -le 1000 ]; do
last=$((RANDOM % 101))
sum=$((sum + last))
done
echo "总和: $sum"
if [ $((last % 3)) -eq 0 ]; then
echo "最后一个数字 $last 能被3整除"
else
echo "最后一个数字 $last 不能被3整除"
fi
42. 判断/tmp目录下是否有大于4k的文件,输出大小与创建时间
find /tmp -type f -size +4k -printf "%s bytes %t\n" 2>/dev/null
43. 检测重要文件是否被修改(使用指纹)
# 生成指纹:md5sum /important/file > file.md5
# 检查脚本
md5sum -c file.md5 &>/dev/null || echo "文件已被修改" | mail -s "Alert" admin@example.com
44. 防止DOS攻击(监控nginx日志,PV过大则封禁IP)
#!/bin/bash
tail -10000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | while read count ip; do
if [ $count -gt 200 ]; then
iptables -I INPUT -s $ip -j DROP
echo "$(date) 封禁 $ip (PV=$count)" >> /var/log/ddos.log
fi
done
45. 实时监控CPU/磁盘/内存使用率 >80% 报警
#!/bin/bash
while true; do
cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
disk=$(df -h / | awk 'NR==2{print $5}' | tr -d '%')
mem=$(free | awk '/Mem:/ {printf "%.0f", $3/$2 * 100}')
[ ${cpu%.*} -gt 80 ] && echo "CPU报警: ${cpu}%"
[ $disk -gt 80 ] && echo "磁盘报警: ${disk}%"
[ $mem -gt 80 ] && echo "内存报警: ${mem}%"
sleep 10
done
46. 使用二进制安装nginx(可重复执行)
#!/bin/bash
[ -f /usr/local/nginx/sbin/nginx ] && echo "nginx already installed" && exit 0
yum install -y gcc make pcre-devel zlib-devel
cd /usr/local/src
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar xf nginx-1.24.0.tar.gz
cd nginx-1.24.0
./configure --prefix=/usr/local/nginx
make && make install
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
echo "nginx installed successfully"
47. 数据库分库分表备份到/tmp下
#!/bin/bash
backup_dir=/tmp/backup
mkdir -p $backup_dir
for db in $(mysql -e "SHOW DATABASES;" | grep -v Database); do
mkdir -p $backup_dir/$db
for table in $(mysql -e "USE $db; SHOW TABLES;" | tail -n +2); do
mysqldump $db $table > $backup_dir/$db/${table}.sql
done
done
48. 显示默认环境变量
env # 或 printenv
49. 函数内设置局部变量
local var=value
50. 显示结果为 $test 的echo命令
echo '\$test'
51. Shell脚本第一行
#!/bin/bash
52. 查看脚本执行过程的参数
bash -x script.sh
sonar-scanner
-Dsonar.projectKey=game
-Dsonar.sources=.
-Dsonar.host.url=http://10.0.0.202:9000
-Dsonar.login=c72a261b3a86d16ba91ccfa0df6879d79ba188e5