shell场景题
目录
1、字符串及数组的操作
字符串截取与拼接
数组操作
2、流程控制
循环处理多个文件
条件判断
3、监控问题
检查服务器的磁盘使用率,并发送告警邮件
cpu使用率
检测进程状态,失败时重启
检测特定文本的变化
关键字检测监控
定时清理临时文件
4、top、free、df
top命令
free命令
df命令
5、脚本处理输入参数
访问命令行参数
处理选项和参数
6、管道pipline机制及其应用
7、awk、grep、sed、find、head、tail、tr、cut的使用
grep:文本搜索工具
常用选项
sed流编辑器
常用选项
find文件查找工具
常用选项
tail 命令
常用选项:
head命令
常用选项:
tr 命令
常用选项:
cut命令
常用选项:
综合例子
查找日志文件中的错误并统计
输出文本第十行
统计词频
1、字符串及数组的操作
字符串截取与拼接
字符串截取:使用 ${变量:起始位置:长度}
进行截取,起始位置:从 0 开始计数。长度:要截取的字符数。 ${变量:offset} 从指定位置到末尾
。
字符串拼接:在 Bash 中只需将两个字符串直接放在一起即可
字符串长度:${#string}
#字符串的截取与拼接
string="hello, world"
echo "sub string ${string:7:5}" #sub string world
echo $(echo $string | cut -d ',' -f 2) #cut截取 world
echo ${string: 2} #llo, world
echo ${string: -3} #rld 字符串末尾开始计算注意空格
#拼接 只需将两个字符串直接放在一起即可
string1="welcome"
echo $string $string1 #hello, world welcome
echo ${#string} #12 字符串长度
echo $(whoami) $(date) #命令拼接
数组操作
操作 | 语法示例 |
---|---|
创建数组 | array=("apple" "banana" "cherry") |
访问元素 | ${array[0]} |
访问所有元素 | ${array[@]} |
获取数组长度 | ${#array[@]} |
遍历数组 | for item in "${array[@]}"; do ... done |
添加元素 | array+=("new_item") |
修改元素 | array[1]="new_value" |
删除元素 | unset array[2] |
数组切片 | ${array[@]:start:length} |
关联数组 | declare -A array; array["key"]="value" |
#!/bin/bash
# 创建数组
fruits=("apple" "banana" "cherry" "date")
# 访问数组
echo "First fruit: ${fruits[0]}"
echo "All fruits: ${fruits[@]}"
echo "Number of fruits: ${#fruits[@]}"
# 遍历数组
echo "Fruits:"
for fruit in "${fruits[@]}"; do
echo "- $fruit"
done
# 修改数组
fruits[1]="blueberry"
fruits+=("elderberry")
# 删除元素
unset fruits[2]
# 打印修改后的数组
echo "Updated fruits: ${fruits[@]}"
# 数组切片
echo "Slice of fruits: ${fruits[@]:1:2}"
# 关联数组示例
declare -A colors
colors=(
["red"]="apple"
["yellow"]="banana"
["purple"]="grape"
)
echo "Colors and fruits:"
for color in "${!colors[@]}"; do
echo "$color: ${colors[$color]}"
done
2、流程控制
循环处理多个文件
#通过循环处理多个文件
files=('f1.txt' "f3.txt" "f2.txt") #files=($(ls *.txt))
for file in "${files[@]}"; do
echo "process $file"
done
#通配符过滤
for file in *.txt; do
echo "process $file"
done
#命令替换
for file in $(find . -name "*.txt"); do
echo "process $file"
done
#递归处理
find . -name "*.txt" | while read file; do
echo "process $file"
done
条件判断
#条件语句
if [ -e "t.txt" ]; then
echo "file exist"
else
echo "no this file"
fi
if [ -r "t.txt" ] && [ -w "t.txt" ]; then
echo "file can read and wirite"
fi
echo "请输入一个文件名:"
read filename
# 使用 if 语句检查文件是否存在
if [ -e "$filename" ]; then
echo "文件 $filename 存在。"
else
echo "文件 $filename 不存在。"
fi
echo "请输入一个数字(1-3):"
read number
# 使用 case 语句根据用户输入执行不同操作
case $number in
1)
echo "你选择了数字 1"
;;
2)
echo "你选择了数字 2"
;;
3)
echo "你选择了数字 3"
;;
*)
echo "无效的选择"
;;
esac
3、监控问题
检查服务器的磁盘使用率,并发送告警邮件
#!/bin/bash
# 设置阈值(例如:80%)
THRESHOLD=80
# 获取磁盘使用率
USAGE=$(df -h / | grep / | awk '{ print $5 }' | sed 's/%//g')
# 检查磁盘使用率是否超过阈值
if [ "$USAGE" -gt "$THRESHOLD" ]; then
# 设置邮件相关信息
TO="recipient@example.com" # 收件人邮箱
SUBJECT="磁盘使用率告警"
MESSAGE="警告:磁盘使用率已达到 ${USAGE}%,超过设定阈值 ${THRESHOLD}%。请及时处理。"
# 发送告警邮件
echo "$MESSAGE" | mail -s "$SUBJECT" "$TO"
echo "告警邮件已发送给 $TO"
else
echo "当前磁盘使用率为 ${USAGE}%,未超过阈值 ${THRESHOLD}%。"
fi
#使用 df -h / 命令获取根目录的磁盘使用情况。
#使用 grep / 过滤出相关行。
#使用 awk '{ print $5 }' 提取使用率字段(例如 80%)。
#使用 sed 's/%//g' 去掉百分号,得到纯数字。
cpu使用率
#!/bin/bash
# 设置监控间隔(单位:秒)
INTERVAL=5
# 设置日志文件路径
LOGFILE="/var/log/cpu_usage.log"
# 输出脚本开始运行的信息
echo "开始监控 CPU 使用率,间隔时间为 ${INTERVAL} 秒。"
echo "监控结果将记录到 ${LOGFILE}。"
# 创建或清空日志文件
echo "时间戳, CPU 使用率 (%)" > $LOGFILE
# 无限循环监控 CPU 使用率
while true; do
# 获取当前时间戳
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 获取 CPU 使用率
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
# 输出当前时间和 CPU 使用率
echo "${TIMESTAMP}, ${CPU_USAGE}" | tee -a $LOGFILE
# 等待指定的间隔
sleep $INTERVAL
done
检测进程状态,失败时重启
#!/bin/bash
# 指定要监控的进程名称
PROCESS_NAME="your_process_name"
# 指定启动进程的命令
START_COMMAND="your_start_command"
# 检查进程是否在运行的函数
check_process() {
pgrep -f "$PROCESS_NAME" > /dev/null 2>&1
return $?
}
# 启动进程的函数
start_process() {
echo "启动进程: $PROCESS_NAME"
eval "$START_COMMAND &"
}
# 主循环
while true; do
if check_process; then
echo "$(date): 进程 $PROCESS_NAME 正在运行"
else
echo "$(date): 进程 $PROCESS_NAME 停止,正在重启..."
start_process
fi
# 每隔 5 秒检查一次
sleep 5
done
检测特定文本的变化
#!/bin/bash
# 要监控的文件
FILE_TO_MONITOR="your_file.txt"
# 上一次文件内容的哈希值
LAST_HASH=""
# 检查文件是否存在
if [ ! -f "$FILE_TO_MONITOR" ]; then
echo "文件 $FILE_TO_MONITOR 不存在。"
exit 1
fi
# 主循环
while true; do
# 计算当前文件内容的哈希值
CURRENT_HASH=$(md5sum "$FILE_TO_MONITOR" | awk '{ print $1 }')
# 检查哈希值是否发生变化
if [ "$CURRENT_HASH" != "$LAST_HASH" ]; then
echo "$(date): 文件 $FILE_TO_MONITOR 内容发生变化。"
LAST_HASH="$CURRENT_HASH"
fi
# 每隔 5 秒检查一次
sleep 5
done
关键字检测监控
#!/bin/bash
# 要监控的文件
FILE_TO_MONITOR="your_file.txt"
# 要监控的关键字
KEYWORD="your_keyword"
# 检查文件是否存在
if [ ! -f "$FILE_TO_MONITOR" ]; then
echo "文件 $FILE_TO_MONITOR 不存在。"
exit 1
fi
# 主循环
while true; do
# 检查文件中是否包含关键字
if grep -q "$KEYWORD" "$FILE_TO_MONITOR"; then
echo "$(date): 文件 $FILE_TO_MONITOR 中包含关键字 '$KEYWORD'。"
fi
# 每隔 5 秒检查一次
sleep 5
done
定时清理临时文件
#!/bin/bash
# 清理 /tmp 目录中的临时文件
# 只保留最近 7 天内的文件,其余文件将被删除
find /tmp -type f -mtime +7 -exec rm -f {} \;
创建定时任务, crontab -e进入编辑, 在 cron
表中,每一行代表一个定时任务,格式如下:* * * * * command_to_execute
每个星号代表一个时间字段,具体含义如下:
- 第一个字段:分钟(0-59)
- 第二个字段:小时(0-23)
- 第三个字段:日(1-31)
- 第四个字段:月份(1-12)
- 第五个字段:星期几(0-7),其中 0 和 7 都代表星期天
0 6 * * 1 /path/to/your/script.sh 每周一上午 6 点执行
crontab -l查看任务, crontab -r删除所有任务,删除特定的话crontab -e进入编辑删除行
4、top、free、df
top命令
top命令用于实时显示系统的进程和资源使用情况。它提供了 CPU、内存、进程等信息的动态视图。
top的输出分为两部分:系统信息和进程信息。
系统信息部分(顶部几行):
- uptime:系统运行时间。
- users:当前登录的用户数。
- load average:系统负载(1分钟、5分钟、15分钟的平均负载)。
- tasks:当前进程的数量(运行、睡眠、停止等状态)。
- CPU:各个 CPU 核心的使用情况(用户、系统、空闲等)。
- Mem:物理内存的使用情况(总量、已用、空闲、缓存等)。
- Swap:交换空间的使用情况。
进程信息部分(下方):
- PID:进程 ID。
- USER:进程所有者。
- PR:优先级。
- NI:nice 值。
- VIRT:虚拟内存使用量。
- RES:常驻内存使用量。
- SHR:共享内存使用量。
- S:进程状态(R:运行,S:睡眠,Z:僵尸等)。
- %CPU:CPU 使用率。
- %MEM:内存使用率。
- TIME+:进程使用的 CPU 时间。
- COMMAND:进程名称。
free命令
free命令用于显示系统的内存使用情况,包括物理内存和交换空间。
输出通常包括以下几列:
- total:总内存。
- used:已用内存。
- free:空闲内存。
- shared:共享内存。
- buff/cache:用于缓存的内存。
- available:可用内存(包括缓存和缓冲区)。
df命令
df命令用于显示文件系统的磁盘空间使用情况,-h选项表示以人类可读的格式显示(自动选择合适的单位)
输出通常包括以下几列:
- Filesystem:文件系统的名称。
- Size:文件系统的总大小。
- Used:已用空间。
- Available:可用空间。
- Use%:已用空间的百分比。
- Mounted on:挂载点。
5、脚本处理输入参数
在 Shell 脚本中处理命令行参数是一个常见的需求。可以使用特殊变量 $1
, $2
, $3
, ... 来访问传递给脚本的参数,$#
用于获取参数的数量,$@
和 $*
用于获取所有参数。以下是一些基本的用法和示例。
访问命令行参数
$1
:第一个参数$2
:第二个参数$3
:第三个参数 ...$#
:参数的数量$@
:所有参数(以独立的字符串形式)$*
:所有参数(作为一个单一的字符串)
#!/bin/bash
# 检查参数数量
if [ $# -lt 2 ]; then
echo "用法: $0 <参数1> <参数2>"
exit 1
fi
# 访问参数
PARAM1=$1
PARAM2=$2
echo "第一个参数: $PARAM1" #第一个参数: arg1
echo "第二个参数: $PARAM2" # 第二个参数: arg2
echo "参数总数: $#" #参数总数: 2
# 遍历所有参数
for param in "$@"; do
echo "$param" # arg1 arg2
done
./script.sh arg1 arg2
处理选项和参数
如果你需要处理带有选项的参数(例如 -f
或 --file
),可以使用 getopts
命令
#!/bin/bash
while getopts "f:n:" opt; do
case $opt in
f)
FILE="$OPTARG"
;;
n)
NAME="$OPTARG"
;;
*)
echo "用法: $0 -f <文件> -n <名称>"
exit 1
;;
esac
done
echo "文件: $FILE"
echo "名称: $NAME"
./script.sh -f file.txt -n JL 输出 文件: myfile.txt 名称: John
6、管道pipline机制及其应用
管道(pipeline)是一种强大的机制,用于将一个命令的输出直接传递给另一个命令作为输入。管道的基本语法是使用竖线符号 |
,它可以将多个命令串联在一起,从而实现复杂的数据处理和操作。
当你在命令行中使用管道时,Shell 会创建一个进程来执行每个命令,并将它们连接在一起。具体来说,管道的工作机制如下:1)第一个命令的标准输出(stdout)被连接到第二个命令的标准输入(stdin)。2)如果有多个命令,它们会依次连接,形成一个链条。3)每个命令在执行时都是独立的进程,Shell 会管理这些进程的创建和销毁。
列出当前目录下的所有文件,并通过 grep 过滤出以 .txt 结尾的文件 ls -l | grep ".txt" |
列出当前运行的所有进程,并通过grep过滤出包含 "bash" 的进程: ps aux | grep "bash" |
cat命令将文件内容输出,wc -l 命令统计行数 cat file.txt | wc -l |
从file中提取第一列,排序并去重: cat data.txt | awk '{print $1}' | sort | uniq |
实时监控系统日志,并过滤出包含 "error" 的行 tail -f /var/log/syslog | grep "error" |
读取csv文件以 , 分割第二列,数值排序到最后一行 cat data.csv | cut -d ',' -f 2 | sort -n | tail -1 |
7、awk、grep、sed、find、head、tail、tr、cut的使用
awk是一个强大的文本处理工具,广泛用于数据提取和报告生成。它可以处理文本文件中的数据,进行模式匹配、字段提取、计算等操作,格式为 awk 'pattern { action }' file
pattern
:匹配模式,可以是正则表达式或条件。action
:对匹配行执行的操作。file
:要处理的文件名。内置变量$0:表示整行文本。$1, $2, ...:表示行中的第一个、第二个、...字段。NR:表示当前行号。NF:表示当前行的字段数。
打印文件所有行 | awk '{ print }' filename.txt |
打印特定字段 | Alice 25 要打印第二列(年龄),可以使用:awk '{ print $2 }' data.txt 要打印文件中的第 1 行和第 3 行, awk 'NR==1 || NR==3' data.txt ( |
条件筛选 | 打印第二列且年龄大于20的行 awk '$2 > 20' data.txt 计算和,第一列是数字: awk '{ sum += $1 } END { print sum }' numbers.txt |
格式输出 | awk '{ printf "Name: %s, Age: %d\n", $1, $2 }' data.txt |
多文件处理 | awk '{ print FILENAME ": " $0 }' f1.txt f2.txt 打印每个文件的内容并在每行前加上文件名 |
grep:文本搜索工具
用于在文件或标准输入中搜索匹配指定模式的行。
常用选项
-i
:忽略大小写。 -v
:反向匹配,输出不匹配的行。
-r
:递归搜索目录中的文件。 -E
:启用扩展正则表达式(ERE)。
-o
:只输出匹配的部分。 -n
:显示匹配行的行号。
grep "error" log.txt # 搜索包含 "error" 的行
grep -i "error" log.txt # 忽略大小写搜索
grep -r "error" /var/log/ # 递归搜索目录中的文件
# 使用正则表达式搜索
grep -E "[0-9]{3}-[0-9]{2}-[0-9]{4}" data.txt
sed流编辑器
用于对文本进行查找、替换、插入、删除等操作,支持正则表达式。
常用选项
s/regex/replacement/
:替换匹配的内容。 -i
:直接修改文件内容。
-n
:禁止自动输出,通常与 p
命令一起使用。p
:打印匹配的行。 d
:删除匹配的行。
sed 's/foo/bar/' file.txt # 替换文件中的 "foo" 为 "bar"
sed 's/foo/bar/g' file.txt # 全局替换
sed -i 's/foo/bar/g' file.txt # 直接修改文件
sed '/^$/d' file.txt # 删除空白行
sed -n '/error/p' log.txt # 打印匹配的行
find文件查找工具
用于在目录树中查找文件,并可以对找到的文件执行操作。
常用选项
-name
:按文件名查找。 -type
:按文件类型查找(f
表示文件,d
表示目录)
-mtime
:按修改时间查找。 -exec
:对找到的文件执行命令。-size
:按文件大小查找。
find . -name "*.txt" # 查找当前目录下的所有 .txt 文件
find . -size +1M # 查找大于 1MB 的文件
# 查找并删除 7 天前的日志文件
find /var/log -name "*.log" -mtime +7 -exec rm {} \;
find . -name "*.jpg" -exec gzip {} \; # 查找并压缩所有 .jpg 文件
工具 | 主要用途 | 特点 | 适用场景 |
---|---|---|---|
grep | 文本搜索 | 快速搜索匹配的行,支持正则表达式 | 查找日志、过滤文本 |
sed | 文本编辑 | 流式编辑,支持查找、替换、插入、删除 | 批量替换文本、删除或修改特定行 |
awk | 文本处理 | 强大的字段处理能力,支持编程 | 处理结构化文本(如 CSV)、数据统计 |
find | 文件查找 | 在目录树中查找文件,支持条件过滤和执行命令 | 查找文件、批量操作文件 |
tail 命令
tail 命令用于显示文件的末尾部分,默认显示最后10行。
常用选项:
-n <行数>:指定显示的行数。例如,tail -n 20 file.txt 显示文件的最后20行 |
-f:实时跟踪文件的新增内容,常用于查看日志文件。例如,tail -f logfile.log |
-c <字节数>:显示文件的最后若干字节。例如,tail -c 100 file.txt 显示文件的最后100字节 |
head命令
head命令用于显示文件的开头部分,默认显示前10行。
常用选项:
-n <行数>:指定显示的行数。例如,head -n 20 file.txt 显示文件的前20行。
-c <字节数>:显示文件的前若干字节。例如,head -c 100 file.txt 显示文件的前100字节。
tr 命令
tr 命令用于转换或删除字符。它通常用于处理文本流。
常用选项:
-d:删除字符。例如,tr -d 'a' 删除所有 a 字符; tr -d '0-9' < file.txt # 删除文件中的所有数字 |
-s:压缩重复字符。例如,tr -s ' ' 将多个连续空格压缩为一个空格 tr 'a-z' 'A-Z' < file.txt # 将文件中的所有小写字母转换为大写字母 |
-c:补集操作,表示对不在指定字符集中的字符进行操作 echo "hello world" | tr -s ' ' # 将多个连续空格压缩为一个空格 |
cut命令
cut命令用于从文件的每一行中提取部分内容。它可以根据字段、字符位置或字节位置进行提取。
常用选项:
|
-f: 指定要提取的字段。eg、提取文件的第1和第3列(假设列以逗号分隔) cut -d ',' -f 1,3 file.csv |
-c: 按字符位置提取。提取每行的第1到第5个字符 cut -c 1-5 file.txt |
-b: 按字节位置提取。提取每行的第1到第5个字节 cut -b 1-5 file.txt |
综合例子
查找日志文件中的错误并统计
# 查找 /var/log 目录下所有 .log 文件
find /var/log -name "*.log" -type f | while read file; do
# 使用 grep 查找包含 "error" 的行
grep "error" "$file" | sed 's/error/ERROR/g' > "${file}.errors"
# 使用 awk 统计错误行数
error_count=$(awk '/ERROR/ { count++ } END { print count }' "${file}.errors")
echo "File: $file, Errors: $error_count"
done
输出文本第十行
#1、awk 实现
awk "NR==10" file.txt
#2、tail 结合head
tail -n +10 file.txt | head -1 #从第10行开始
#3、sed -n选项取消sed默认的输出,'10p'指定只打印第10行
sed -n '10p' file.txt
#基本操作
cnt=0
while read line && [ $cnt -le 10 ];
do
let 'cnt = cnt + 1' # cnt=$((cnt + 1))
if [ $cnt -eq 10 ]; then
echo $line
exit 0
fi
done < file.txt
统计词频
cat words.txt| tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{print $2, $1}'