30天Shell脚本编程实战(14天逆袭)

30天Shell脚本编程实战

Day 1: 基础脚本 - Hello World

bash 复制代码
#!/bin/bash
# 第一个Shell脚本,输出Hello World

# 输出文本到终端
echo "Hello, World!"

# 输出当前日期
date

# 显示当前工作目录
pwd

运行结果:

复制代码
Hello, World!
Tue Dec 25 10:00:00 UTC 2024
/home/user

Day 2: 变量和用户输入

bash 复制代码
#!/bin/bash
# 变量使用和用户输入示例

# 提示用户输入姓名
read -p "请输入你的名字: " username

# 提示用户输入年龄
read -p "请输入你的年龄: " age

# 使用变量
echo "你好, $username!"
echo "你今年 $age 岁"

# 计算出生年份
current_year=$(date +%Y)
birth_year=$((current_year - age))
echo "你的出生年份大约是 $birth_year 年"

# 显示变量信息
echo "用户名变量类型: ${username@a}"
echo "年龄变量值: $age"

运行示例:

复制代码
请输入你的名字: 张三
请输入你的年龄: 25
你好, 张三!
你今年 25 岁
你的出生年份大约是 1999 年
用户名变量类型: 
年龄变量值: 25

Day 3: 数学运算

bash 复制代码
#!/bin/bash
# 数学运算示例

echo "=== 基础数学运算 ==="

# 定义变量
num1=15
num2=4

# 加法
sum=$((num1 + num2))
echo "$num1 + $num2 = $sum"

# 减法
diff=$((num1 - num2))
echo "$num1 - $num2 = $diff"

# 乘法
prod=$((num1 * num2))
echo "$num1 * $num2 = $prod"

# 除法(整数)
div=$((num1 / num2))
echo "$num1 / $num2 = $div (整数除法)"

# 取余
mod=$((num1 % num2))
echo "$num1 % $num2 = $mod"

# 指数运算
power=$((num1 ** 2))
echo "$num1 ^ 2 = $power"

echo -e "\n=== 浮点数运算 ==="
# 使用bc进行浮点运算
float_div=$(echo "scale=2; $num1 / $num2" | bc)
echo "$num1 / $num2 = $float_div (浮点除法)"

# 平方根
sqrt=$(echo "scale=2; sqrt($num1)" | bc -l)
echo "√$num1 ≈ $sqrt"

echo -e "\n=== 递增递减 ==="
counter=5
echo "初始值: $counter"
((counter++))
echo "递增后: $counter"
((counter--))
echo "递减后: $counter"

运行结果:

复制代码
=== 基础数学运算 ===
15 + 4 = 19
15 - 4 = 11
15 * 4 = 60
15 / 4 = 3 (整数除法)
15 % 4 = 3
15 ^ 2 = 225

=== 浮点数运算 ===
15 / 4 = 3.75 (浮点除法)
√15 ≈ 3.87

=== 递增递减 ===
初始值: 5
递增后: 6
递减后: 5

Day 4: 条件判断

bash 复制代码
#!/bin/bash
# 条件判断示例

echo "=== 数值比较 ==="
read -p "请输入第一个数字: " a
read -p "请输入第二个数字: " b

if [ $a -eq $b ]; then
    echo "$a 等于 $b"
fi

if [ $a -ne $b ]; then
    echo "$a 不等于 $b"
fi

if [ $a -gt $b ]; then
    echo "$a 大于 $b"
elif [ $a -lt $b ]; then
    echo "$a 小于 $b"
else
    echo "$a 等于 $b"
fi

echo -e "\n=== 字符串比较 ==="
read -p "请输入第一个字符串: " str1
read -p "请输入第二个字符串: " str2

if [ "$str1" = "$str2" ]; then
    echo "字符串相同"
else
    echo "字符串不同"
fi

if [ -z "$str1" ]; then
    echo "第一个字符串为空"
fi

if [ -n "$str2" ]; then
    echo "第二个字符串非空"
fi

echo -e "\n=== 文件检查 ==="
filename="test.txt"
echo "创建测试文件..."
echo "测试内容" > $filename

if [ -e $filename ]; then
    echo "文件存在"
    
    if [ -f $filename ]; then
        echo "是普通文件"
    fi
    
    if [ -r $filename ]; then
        echo "文件可读"
    fi
    
    if [ -w $filename ]; then
        echo "文件可写"
    fi
    
    if [ -s $filename ]; then
        echo "文件大小: $(wc -c < $filename) 字节"
    fi
fi

# 清理
rm $filename

运行示例:

复制代码
=== 数值比较 ===
请输入第一个数字: 10
请输入第二个数字: 5
10 不等于 5
10 大于 5

=== 字符串比较 ===
请输入第一个字符串: hello
请输入第二个字符串: world
字符串不同
第二个字符串非空

=== 文件检查 ===
创建测试文件...
文件存在
是普通文件
文件可读
文件可写
文件大小: 13 字节

Day 5: 逻辑运算符

bash 复制代码
#!/bin/bash
# 逻辑运算符示例

echo "=== 逻辑运算符使用 ==="

read -p "请输入年龄: " age
read -p "是否有会员卡?(yes/no): " member

# AND 运算符
if [ $age -ge 18 ] && [ "$member" = "yes" ]; then
    echo "可以享受会员折扣"
else
    echo "不符合会员折扣条件"
fi

# OR 运算符
if [ $age -lt 12 ] || [ $age -ge 65 ]; then
    echo "可以享受特殊优惠"
else
    echo "不符合特殊优惠条件"
fi

# NOT 运算符
if ! [ "$member" = "no" ]; then
    echo "你有会员身份"
else
    echo "你不是会员"
fi

echo -e "\n=== 复合条件 ==="
read -p "请输入分数(0-100): " score

if [ $score -ge 90 ]; then
    grade="A"
elif [ $score -ge 80 ] && [ $score -lt 90 ]; then
    grade="B"
elif [ $score -ge 70 ] && [ $score -lt 80 ]; then
    grade="C"
elif [ $score -ge 60 ] && [ $score -lt 70 ]; then
    grade="D"
else
    grade="F"
fi

echo "你的成绩等级是: $grade"

echo -e "\n=== 简化写法 ==="
# 使用双括号简化
if (( age >= 18 && age <= 30 )); then
    echo "你是青年人"
fi

# 使用双方括号进行模式匹配
read -p "请输入文件名: " filename
if [[ $filename == *.txt ]]; then
    echo "这是一个文本文件"
elif [[ $filename == *.jpg || $filename == *.png ]]; then
    echo "这是一个图片文件"
else
    echo "文件类型未知"
fi

运行示例:

复制代码
=== 逻辑运算符使用 ===
请输入年龄: 25
是否有会员卡?(yes/no): yes
可以享受会员折扣
不符合特殊优惠条件
你有会员身份

=== 复合条件 ===
请输入分数(0-100): 85
你的成绩等级是: B

=== 简化写法 ===
你是青年人
请输入文件名: document.txt
这是一个文本文件

Day 6: Case语句

bash 复制代码
#!/bin/bash
# Case语句示例

echo "=== 基础Case语句 ==="
read -p "请输入一个数字(1-7): " day

case $day in
    1)
        echo "星期一"
        ;;
    2)
        echo "星期二"
        ;;
    3)
        echo "星期三"
        ;;
    4)
        echo "星期四"
        ;;
    5)
        echo "星期五"
        ;;
    6|7)
        echo "周末"
        ;;
    *)
        echo "输入无效"
        ;;
esac

echo -e "\n=== 文件类型判断 ==="
read -p "请输入文件名: " filename

case $filename in
    *.txt)
        echo "文本文件"
        ;;
    *.sh)
        echo "Shell脚本"
        ;;
    *.jpg|*.jpeg|*.png|*.gif)
        echo "图片文件"
        ;;
    *.tar|*.tar.gz|*.zip)
        echo "压缩文件"
        ;;
    *)
        echo "未知文件类型"
        ;;
esac

echo -e "\n=== 系统命令菜单 ==="
echo "请选择操作:"
echo "1. 显示系统信息"
echo "2. 显示磁盘使用"
echo "3. 显示内存使用"
echo "4. 显示网络连接"
echo "5. 退出"

read -p "请输入选项(1-5): " option

case $option in
    1)
        echo "=== 系统信息 ==="
        uname -a
        ;;
    2)
        echo "=== 磁盘使用 ==="
        df -h
        ;;
    3)
        echo "=== 内存使用 ==="
        free -h
        ;;
    4)
        echo "=== 网络连接 ==="
        netstat -tuln | head -20
        ;;
    5)
        echo "退出程序"
        exit 0
        ;;
    *)
        echo "无效选项"
        ;;
esac

运行示例:

复制代码
=== 基础Case语句 ===
请输入一个数字(1-7): 3
星期三

=== 文件类型判断 ===
请输入文件名: script.sh
Shell脚本

=== 系统命令菜单 ===
请选择操作:
1. 显示系统信息
2. 显示磁盘使用
3. 显示内存使用
4. 显示网络连接
5. 退出
请输入选项(1-5): 1
=== 系统信息 ===
Linux server 5.4.0-100-generic #113-Ubuntu SMP Thu Feb 3 18:43:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Day 7: For循环

bash 复制代码
#!/bin/bash
# For循环示例

echo "=== 基础For循环 ==="
echo "数字列表:"
for i in 1 2 3 4 5; do
    echo "数字: $i"
done

echo -e "\n=== 范围循环 ==="
echo "1到5:"
for i in {1..5}; do
    echo "迭代: $i"
done

echo -e "\n带步长的循环:"
for i in {1..10..2}; do
    echo "奇数: $i"
done

echo -e "\n=== C风格For循环 ==="
for ((i=1; i<=5; i++)); do
    echo "计数: $i"
done

echo -e "\n=== 遍历数组 ==="
fruits=("苹果" "香蕉" "橙子" "葡萄" "西瓜")
echo "水果列表:"
for fruit in "${fruits[@]}"; do
    echo "  - $fruit"
done

echo -e "\n=== 遍历文件 ==="
echo "当前目录文件:"
for file in *; do
    if [ -f "$file" ]; then
        echo "  文件: $file"
    elif [ -d "$file" ]; then
        echo "  目录: $file"
    fi
done

echo -e "\n=== 嵌套循环 ==="
echo "乘法表 (1-3):"
for i in {1..3}; do
    for j in {1..3}; do
        result=$((i * j))
        echo -n "$i×$j=$result  "
    done
    echo  # 换行
done

echo -e "\n=== 带条件的循环 ==="
echo "小于5的偶数:"
for i in {1..10}; do
    if (( i % 2 == 0 && i < 5 )); then
        echo "找到偶数: $i"
    fi
done

运行结果:

复制代码
=== 基础For循环 ===
数字列表:
数字: 1
数字: 2
数字: 3
数字: 4
数字: 5

=== 范围循环 ===
1到5:
迭代: 1
迭代: 2
迭代: 3
迭代: 4
迭代: 5

带步长的循环:
奇数: 1
奇数: 3
奇数: 5
奇数: 7
奇数: 9

=== C风格For循环 ===
计数: 1
计数: 2
计数: 3
计数: 4
计数: 5

=== 遍历数组 ===
水果列表:
  - 苹果
  - 香蕉
  - 橙子
  - 葡萄
  - 西瓜

=== 遍历文件 ===
当前目录文件:
  文件: script.sh
  目录: docs

=== 嵌套循环 ===
乘法表 (1-3):
1×1=1  1×2=2  1×3=3  
2×1=2  2×2=4  2×3=6  
3×1=3  3×2=6  3×3=9  

=== 带条件的循环 ===
小于5的偶数:
找到偶数: 2
找到偶数: 4

Day 8: While循环

bash 复制代码
#!/bin/bash
# While循环示例

echo "=== 基础While循环 ==="
counter=1
echo "从1数到5:"
while [ $counter -le 5 ]; do
    echo "计数: $counter"
    ((counter++))
done

echo -e "\n=== 读取文件内容 ==="
# 创建测试文件
cat > students.txt << EOF
张三
李四
王五
赵六
EOF

echo "学生名单:"
while read student; do
    echo "  - $student"
done < students.txt

echo -e "\n=== 无限循环控制 ==="
echo "猜数字游戏 (1-10)"
secret=$((RANDOM % 10 + 1))
attempts=0

while true; do
    read -p "请输入你的猜测: " guess
    ((attempts++))
    
    if [ $guess -eq $secret ]; then
        echo "恭喜!猜对了!"
        echo "你用了 $attempts 次尝试"
        break
    elif [ $guess -lt $secret ]; then
        echo "猜小了,再试试"
    else
        echo "猜大了,再试试"
    fi
    
    if [ $attempts -ge 5 ]; then
        echo "机会用完了!正确答案是: $secret"
        break
    fi
done

echo -e "\n=== 条件循环 ==="
total=0
count=0
echo "输入数字求平均 (输入0结束):"

while read -p "请输入数字: " num && [ $num -ne 0 ]; do
    total=$((total + num))
    count=$((count + 1))
    echo "当前总和: $total, 数字个数: $count"
done

if [ $count -gt 0 ]; then
    average=$((total / count))
    echo "平均值为: $average"
else
    echo "没有输入数字"
fi

# 清理
rm students.txt

运行示例:

复制代码
=== 基础While循环 ===
从1数到5:
计数: 1
计数: 2
计数: 3
计数: 4
计数: 5

=== 读取文件内容 ===
学生名单:
  - 张三
  - 李四
  - 王五
  - 赵六

=== 无限循环控制 ===
猜数字游戏 (1-10)
请输入你的猜测: 5
猜小了,再试试
请输入你的猜测: 8
猜大了,再试试
请输入你的猜测: 7
猜大了,再试试
请输入你的猜测: 6
恭喜!猜对了!
你用了 4 次尝试

=== 条件循环 ===
输入数字求平均 (输入0结束):
请输入数字: 10
当前总和: 10, 数字个数: 1
请输入数字: 20
当前总和: 30, 数字个数: 2
请输入数字: 30
当前总和: 60, 数字个数: 3
请输入数字: 0
平均值为: 20

Day 9: 数组操作

bash 复制代码
#!/bin/bash
# 数组操作示例

echo "=== 数组基本操作 ==="

# 定义数组
colors=("红色" "绿色" "蓝色" "黄色" "紫色")

echo "颜色数组: ${colors[@]}"
echo "数组长度: ${#colors[@]}"
echo "第一个颜色: ${colors[0]}"
echo "最后一个颜色: ${colors[-1]}"

echo -e "\n=== 遍历数组 ==="
echo "所有颜色:"
for color in "${colors[@]}"; do
    echo "  - $color"
done

echo -e "\n带索引的遍历:"
for i in "${!colors[@]}"; do
    echo "  索引 $i: ${colors[$i]}"
done

echo -e "\n=== 数组操作 ==="
# 添加元素
colors+=("橙色")
echo "添加橙色后: ${colors[@]}"

# 修改元素
colors[1]="深绿色"
echo "修改第二个元素后: ${colors[@]}"

# 删除元素
unset colors[2]
echo "删除第三个元素后: ${colors[@]}"

# 重新索引
colors=("${colors[@]}")
echo "重新索引后长度: ${#colors[@]}"

echo -e "\n=== 关联数组 ==="
declare -A student_scores
student_scores["张三"]=90
student_scores["李四"]=85
student_scores["王五"]=95

echo "学生成绩:"
for name in "${!student_scores[@]}"; do
    echo "  $name: ${student_scores[$name]}分"
done

echo -e "\n=== 数组排序 ==="
numbers=(45 12 89 3 67 23)
echo "原始数组: ${numbers[@]}"

# 冒泡排序
sorted=($(for num in "${numbers[@]}"; do echo $num; done | sort -n))
echo "排序后: ${sorted[@]}"

echo -e "\n=== 多维数组模拟 ==="
# 使用关联数组模拟二维数组
declare -A matrix
matrix[0,0]=1
matrix[0,1]=2
matrix[1,0]=3
matrix[1,1]=4

echo "矩阵:"
echo "  ${matrix[0,0]} ${matrix[0,1]}"
echo "  ${matrix[1,0]} ${matrix[1,1]}"

echo -e "\n=== 数组切片 ==="
original=("a" "b" "c" "d" "e" "f")
slice=("${original[@]:1:3}")  # 从索引1开始取3个元素
echo "原始数组: ${original[@]}"
echo "切片(1-3): ${slice[@]}"

运行结果:

复制代码
=== 数组基本操作 ===
颜色数组: 红色 绿色 蓝色 黄色 紫色
数组长度: 5
第一个颜色: 红色
最后一个颜色: 紫色

=== 遍历数组 ===
所有颜色:
  - 红色
  - 绿色
  - 蓝色
  - 黄色
  - 紫色

带索引的遍历:
  索引 0: 红色
  索引 1: 绿色
  索引 2: 蓝色
  索引 3: 黄色
  索引 4: 紫色

=== 数组操作 ===
添加橙色后: 红色 绿色 蓝色 黄色 紫色 橙色
修改第二个元素后: 红色 深绿色 蓝色 黄色 紫色 橙色
删除第三个元素后: 红色 深绿色 黄色 紫色 橙色
重新索引后长度: 5

=== 关联数组 ===
学生成绩:
  李四: 85分
  王五: 95分
  张三: 90分

=== 数组排序 ===
原始数组: 45 12 89 3 67 23
排序后: 3 12 23 45 67 89

=== 多维数组模拟 ===
矩阵:
  1 2
  3 4

=== 数组切片 ===
原始数组: a b c d e f
切片(1-3): b c d

Day 10: 函数使用

bash 复制代码
#!/bin/bash
# 函数示例

echo "=== 基础函数 ==="

# 定义函数
greet() {
    local name=$1
    echo "你好,$name!"
    echo "欢迎使用Shell脚本!"
}

# 调用函数
greet "张三"
greet "李四"

echo -e "\n=== 函数参数 ==="
calculate_sum() {
    local sum=0
    for num in "$@"; do
        sum=$((sum + num))
    done
    echo $sum
}

result=$(calculate_sum 1 2 3 4 5)
echo "1+2+3+4+5 = $result"

echo -e "\n=== 函数返回值 ==="
is_even() {
    local num=$1
    if [ $((num % 2)) -eq 0 ]; then
        return 0  # 真
    else
        return 1  # 假
    fi
}

check_number() {
    read -p "请输入一个数字: " num
    if is_even $num; then
        echo "$num 是偶数"
    else
        echo "$num 是奇数"
    fi
}

check_number

echo -e "\n=== 递归函数 ==="
factorial() {
    local n=$1
    if [ $n -le 1 ]; then
        echo 1
    else
        local prev=$(factorial $((n - 1)))
        echo $((n * prev))
    fi
}

echo "5的阶乘: $(factorial 5)"

echo -e "\n=== 函数库示例 ==="
# 定义数学函数库
math_lib() {
    case $1 in
        add)
            echo $(($2 + $3))
            ;;
        subtract)
            echo $(($2 - $3))
            ;;
        multiply)
            echo $(($2 * $3))
            ;;
        divide)
            if [ $3 -ne 0 ]; then
                echo $(($2 / $3))
            else
                echo "错误:除数不能为0"
            fi
            ;;
        *)
            echo "未知操作"
            ;;
    esac
}

echo "10 + 5 = $(math_lib add 10 5)"
echo "10 - 5 = $(math_lib subtract 10 5)"
echo "10 * 5 = $(math_lib multiply 10 5)"
echo "10 / 5 = $(math_lib divide 10 5)"
echo "10 / 0 = $(math_lib divide 10 0)"

echo -e "\n=== 局部变量 ==="
test_scope() {
    local local_var="我是局部变量"
    global_var="我是全局变量"
    echo "函数内 - 局部变量: $local_var"
    echo "函数内 - 全局变量: $global_var"
}

test_scope
echo "函数外 - 局部变量: $local_var"  # 输出空
echo "函数外 - 全局变量: $global_var"

运行示例:

复制代码
=== 基础函数 ===
你好,张三!
欢迎使用Shell脚本!
你好,李四!
欢迎使用Shell脚本!

=== 函数参数 ===
1+2+3+4+5 = 15

=== 函数返回值 ===
请输入一个数字: 7
7 是奇数

=== 递归函数 ===
5的阶乘: 120

=== 函数库示例 ===
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10 / 5 = 2
10 / 0 = 错误:除数不能为0

=== 局部变量 ===
函数内 - 局部变量: 我是局部变量
函数内 - 全局变量: 我是全局变量
函数外 - 局部变量: 
函数外 - 全局变量: 我是全局变量

Day 11: 文件操作

bash 复制代码
#!/bin/bash
# 文件操作示例

echo "=== 文件创建和写入 ==="

# 创建并写入文件
echo "这是第一行" > test.txt
echo "这是第二行" >> test.txt
echo "这是第三行" >> test.txt

echo "文件内容:"
cat test.txt

echo -e "\n=== 文件读取 ==="
echo "逐行读取:"
line_num=1
while IFS= read -r line; do
    echo "行 $line_num: $line"
    ((line_num++))
done < test.txt

echo -e "\n=== 文件信息 ==="
echo "文件大小: $(wc -c < test.txt) 字节"
echo "行数: $(wc -l < test.txt)"
echo "单词数: $(wc -w < test.txt)"

echo -e "\n=== 文件查找和替换 ==="
# 查找包含"第二"的行
echo "包含'第二'的行:"
grep "第二" test.txt

# 替换文件内容
sed 's/第二/贰/' test.txt > test_modified.txt
echo "替换后的内容:"
cat test_modified.txt

echo -e "\n=== 文件比较 ==="
echo "比较两个文件差异:"
diff test.txt test_modified.txt

echo -e "\n=== 目录操作 ==="
mkdir -p test_dir/sub_dir
echo "创建目录结构完成"
echo "目录内容:"
ls -la test_dir/

echo -e "\n=== 文件权限 ==="
chmod 755 test.txt
echo "文件权限:"
ls -l test.txt

echo -e "\n=== 文件移动和重命名 ==="
mv test.txt renamed.txt
echo "文件重命名完成:"
ls -l *.txt

echo -e "\n=== 文件删除 ==="
rm renamed.txt test_modified.txt
rm -rf test_dir
echo "清理完成"

运行结果:

复制代码
=== 文件创建和写入 ===
文件内容:
这是第一行
这是第二行
这是第三行

=== 文件读取 ===
逐行读取:
行 1: 这是第一行
行 2: 这是第二行
行 3: 这是第三行

=== 文件信息 ===
文件大小: 39 字节
行数: 3
单词数: 9

=== 文件查找和替换 ===
包含'第二'的行:
这是第二行
替换后的内容:
这是第一行
这是贰行
这是第三行

=== 文件比较 ===
比较两个文件差异:
2c2
< 这是第二行
---
> 这是贰行

=== 目录操作 ===
创建目录结构完成
目录内容:
总用量 8
drwxr-xr-x 3 user user 4096 Dec 25 10:30 .
drwxr-xr-x 4 user user 4096 Dec 25 10:30 ..
drwxr-xr-x 2 user user 4096 Dec 25 10:30 sub_dir

=== 文件权限 ===
文件权限:
-rwxr-xr-x 1 user user 39 Dec 25 10:30 test.txt

=== 文件移动和重命名 ===
文件重命名完成:
-rwxr-xr-x 1 user user 39 Dec 25 10:30 renamed.txt
-rw-r--r-- 1 user user 39 Dec 25 10:30 test_modified.txt

=== 文件删除 ===
清理完成

Day 12: 文本处理

bash 复制代码
#!/bin/bash
# 文本处理示例

echo "=== 创建测试数据 ==="
cat > data.txt << EOF
张三,25,工程师,北京
李四,30,设计师,上海
王五,28,产品经理,深圳
赵六,35,经理,广州
钱七,22,实习生,杭州
EOF

echo "原始数据:"
cat data.txt

echo -e "\n=== 文本过滤 ==="
echo "年龄大于25岁的员工:"
awk -F, '$2 > 25' data.txt

echo -e "\n=== 文本排序 ==="
echo "按年龄排序:"
sort -t, -k2,2n data.txt

echo -e "\n按姓名排序:"
sort -t, -k1,1 data.txt

echo -e "\n=== 文本统计 ==="
echo "各职位人数统计:"
awk -F, '{count[$3]++} END {for(job in count) print job ": " count[job] "人"}' data.txt

echo -e "\n=== 文本转换 ==="
echo "转换为HTML表格:"
echo "<table border='1'>"
echo "<tr><th>姓名</th><th>年龄</th><th>职位</th><th>城市</th></tr>"
awk -F, '{print "<tr><td>" $1 "</td><td>" $2 "</td><td>" $3 "</td><td>" $4 "</td></tr>"}' data.txt
echo "</table>"

echo -e "\n=== 字段提取 ==="
echo "提取姓名和职位:"
cut -d, -f1,3 data.txt

echo -e "\n=== 文本搜索 ==="
echo "查找'经理':"
grep "经理" data.txt

echo -e "\n=== 文本替换 ==="
echo "将'经理'替换为'主管':"
sed 's/经理/主管/g' data.txt

echo -e "\n=== 去重处理 ==="
echo "添加重复数据..."
echo "张三,25,工程师,北京" >> data.txt
echo "去重后:"
sort data.txt | uniq

echo -e "\n=== 行号处理 ==="
echo "显示行号:"
nl data.txt

echo -e "\n=== 合并文件 ==="
cat > extra_data.txt << EOF
孙八,40,总监,南京
周九,26,开发,成都
EOF

echo "合并后的数据:"
cat data.txt extra_data.txt

# 清理
rm data.txt extra_data.txt

运行结果:

复制代码
=== 创建测试数据 ===
原始数据:
张三,25,工程师,北京
李四,30,设计师,上海
王五,28,产品经理,深圳
赵六,35,经理,广州
钱七,22,实习生,杭州

=== 文本过滤 ===
年龄大于25岁的员工:
李四,30,设计师,上海
王五,28,产品经理,深圳
赵六,35,经理,广州

=== 文本排序 ===
按年龄排序:
钱七,22,实习生,杭州
张三,25,工程师,北京
王五,28,产品经理,深圳
李四,30,设计师,上海
赵六,35,经理,广州

按姓名排序:
李四,30,设计师,上海
王五,28,产品经理,深圳
钱七,22,实习生,杭州
张三,25,工程师,北京
赵六,35,经理,广州

=== 文本统计 ===
各职位人数统计:
设计师: 1人
产品经理: 1人
经理: 1人
工程师: 1人
实习生: 1人

=== 文本转换 ===
转换为HTML表格:
<table border='1'>
<tr><th>姓名</th><th>年龄</th><th>职位</th><th>城市</th></tr>
<tr><td>张三</td><td>25</td><td>工程师</td><td>北京</td></tr>
<tr><td>李四</td><td>30</td><td>设计师</td><td>上海</td></tr>
<tr><td>王五</td><td>28</td><td>产品经理</td><td>深圳</td></tr>
<tr><td>赵六</td><td>35</td><td>经理</td><td>广州</td></tr>
<tr><td>钱七</td><td>22</td><td>实习生</td><td>杭州</td></tr>
</table>

=== 字段提取 ===
提取姓名和职位:
张三,工程师
李四,设计师
王五,产品经理
赵六,经理
钱七,实习生

=== 文本搜索 ===
查找'经理':
王五,28,产品经理,深圳
赵六,35,经理,广州

=== 文本替换 ===
将'经理'替换为'主管':
张三,25,工程师,北京
李四,30,设计师,上海
王五,28,产品主管,深圳
赵六,35,主管,广州
钱七,22,实习生,杭州

=== 去重处理 ===
添加重复数据...
去重后:
张三,25,工程师,北京
李四,30,设计师,上海
王五,28,产品经理,深圳
赵六,35,经理,广州
钱七,22,实习生,杭州

=== 行号处理 ===
显示行号:
     1  张三,25,工程师,北京
     2  李四,30,设计师,上海
     3  王五,28,产品经理,深圳
     4  赵六,35,经理,广州
     5  钱七,22,实习生,杭州
     6  张三,25,工程师,北京

=== 合并文件 ===
合并后的数据:
张三,25,工程师,北京
李四,30,设计师,上海
王五,28,产品经理,深圳
赵六,35,经理,广州
钱七,22,实习生,杭州
张三,25,工程师,北京
孙八,40,总监,南京
周九,26,开发,成都

Day 13: 正则表达式

bash 复制代码
#!/bin/bash
# 正则表达式示例

echo "=== 创建测试数据 ==="
cat > text.txt << EOF
我的电话是: 138-1234-5678
电子邮件: john.doe@example.com
另一个邮箱: alice_smith123@gmail.com
URL: https://www.example.com/page
IP地址: 192.168.1.1
日期: 2024-12-25
时间: 14:30:45
身份证: 110101199001011234
邮政编码: 100000
EOF

echo "测试文本内容:"
cat text.txt

echo -e "\n=== 基础匹配 ==="
echo "查找所有邮箱地址:"
grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' text.txt

echo -e "\n查找所有电话号码:"
grep -E '[0-9]{3}-[0-9]{4}-[0-9]{4}' text.txt

echo -e "\n=== 复杂匹配 ==="
echo "查找URL:"
grep -E 'https?://[a-zA-Z0-9./?=_%:-]+' text.txt

echo -e "\n查找IP地址:"
grep -E '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' text.txt

echo -e "\n查找日期:"
grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' text.txt

echo -e "\n=== 使用sed进行替换 ==="
echo "隐藏电话号码中间四位:"
sed -E 's/([0-9]{3}-)[0-9]{4}(-[0-9]{4})/\1****\2/' text.txt

echo -e "\n隐藏邮箱用户名:"
sed -E 's/([a-zA-Z0-9._%+-]+)@/@/' text.txt | sed 's/@/@***/' | sed 's/@***/@***./'

echo -e "\n=== 使用awk提取 ==="
echo "提取时间部分:"
awk 'match($0, /([0-9]{2}:[0-9]{2}:[0-9]{2})/, arr) {print arr[1]}' text.txt

echo -e "\n=== 分组捕获 ==="
echo "提取日期各部分:"
grep -E '([0-9]{4})-([0-9]{2})-([0-9]{2})' text.txt | while read line; do
    if [[ $line =~ ([0-9]{4})-([0-9]{2})-([0-9]{2}) ]]; then
        echo "年: ${BASH_REMATCH[1]}, 月: ${BASH_REMATCH[2]}, 日: ${BASH_REMATCH[3]}"
    fi
done

echo -e "\n=== 验证格式 ==="
echo "验证身份证格式 (18位):"
grep -E '^[1-9][0-9]{5}(18|19|20)[0-9]{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)[0-9]{3}[0-9Xx]$' text.txt

echo -e "\n验证邮政编码 (6位数字):"
grep -E '^[1-9][0-9]{5}$' text.txt

echo -e "\n=== 负向匹配 ==="
echo "查找不含数字的行:"
grep -v '[0-9]' text.txt

echo -e "\n=== 边界匹配 ==="
echo "查找以'我的'开头的行:"
grep '^我的' text.txt

echo "查找以'com'结尾的行:"
grep 'com$' text.txt

# 清理
rm text.txt

运行结果:

复制代码
=== 创建测试数据 ===
测试文本内容:
我的电话是: 138-1234-5678
电子邮件: john.doe@example.com
另一个邮箱: alice_smith123@gmail.com
URL: https://www.example.com/page
IP地址: 192.168.1.1
日期: 2024-12-25
时间: 14:30:45
身份证: 110101199001011234
邮政编码: 100000

=== 基础匹配 ===
查找所有邮箱地址:
电子邮件: john.doe@example.com
另一个邮箱: alice_smith123@gmail.com

查找所有电话号码:
我的电话是: 138-1234-5678

=== 复杂匹配 ===
查找URL:
URL: https://www.example.com/page

查找IP地址:
IP地址: 192.168.1.1

查找日期:
日期: 2024-12-25

=== 使用sed进行替换 ===
隐藏电话号码中间四位:
我的电话是: 138-****-5678
电子邮件: john.doe@example.com
另一个邮箱: alice_smith123@gmail.com
URL: https://www.example.com/page
IP地址: 192.168.1.1
日期: 2024-12-25
时间: 14:30:45
身份证: 110101199001011234
邮政编码: 100000

隐藏邮箱用户名:
我的电话是: 138-1234-5678
电子邮件: @***.example.com
另一个邮箱: @***.gmail.com
URL: https://www.example.com/page
IP地址: 192.168.1.1
日期: 2024-12-25
时间: 14:30:45
身份证: 110101199001011234
邮政编码: 100000

=== 使用awk提取 ===
提取时间部分:
14:30:45

=== 分组捕获 ===
提取日期各部分:
年: 2024, 月: 12, 日: 25

=== 验证格式 ===
验证身份证格式 (18位):
身份证: 110101199001011234

验证邮政编码 (6位数字):
邮政编码: 100000

=== 负向匹配 ===
查找不含数字的行:
(没有输出)

=== 边界匹配 ===
查找以'我的'开头的行:
我的电话是: 138-1234-5678

查找以'com'结尾的行:
电子邮件: john.doe@example.com
另一个邮箱: alice_smith123@gmail.com

Day 14: 进程管理

bash 复制代码
#!/bin/bash
# 进程管理示例

echo "=== 进程信息 ==="
echo "当前Shell的PID: $$"
echo "父进程PID: $PPID"
echo "当前用户: $(whoami)"

echo -e "\n=== 运行进程 ==="
echo "在后台运行sleep命令:"
sleep 10 &
sleep_pid=$!
echo "sleep进程PID: $sleep_pid"

echo -e "\n运行多个后台进程:"
for i in {1..3}; do
    sleep 5 &
    echo "启动进程 $i, PID: $!"
done

echo -e "\n=== 进程列表 ==="
echo "当前用户进程:"
ps -u $(whoami) | head -10

echo -e "\n进程树:"
pstree -p $(whoami) | head -15

echo -e "\n=== 进程监控 ==="
echo "CPU使用率最高的进程:"
ps aux --sort=-%cpu | head -5

echo -e "\n内存使用率最高的进程:"
ps aux --sort=-%mem | head -5

echo -e "\n=== 进程控制 ==="
echo "等待sleep进程完成:"
wait $sleep_pid
echo "sleep进程已完成"

echo -e "\n启动一个长时间运行的进程:"
echo "运行ping命令 (5秒后停止)..."
ping -c 10 google.com > /dev/null &
ping_pid=$!

sleep 5
echo "停止ping进程 (PID: $ping_pid)"
kill $ping_pid
if wait $ping_pid 2>/dev/null; then
    echo "进程正常结束"
else
    echo "进程被终止"
fi

echo -e "\n=== 作业控制 ==="
echo "启动两个作业:"
sleep 20 &
job1=$!
echo "作业1 (sleep 20): PID=$job1"

sleep 30 &
job2=$!
echo "作业2 (sleep 30): PID=$job2"

echo -e "\n作业列表:"
jobs

echo -e "\n将作业2放到前台:"
fg %2 &
sleep 2

echo -e "\n将作业2放回后台:"
bg %2

echo -e "\n终止所有sleep进程:"
pkill sleep
echo "已终止所有sleep进程"

echo -e "\n=== 进程间通信 ==="
echo "创建命名管道:"
mkfifo my_pipe
echo "通过管道发送数据..."
echo "Hello from process 1" > my_pipe &
cat my_pipe &
wait

rm my_pipe

echo -e "\n=== 信号处理 ==="
trap "echo '收到SIGINT信号'; exit 1" SIGINT
trap "echo '收到SIGTERM信号'; exit 1" SIGTERM

echo "按Ctrl+C发送SIGINT信号"
echo "等待5秒..."
sleep 5
echo "没有收到信号,继续执行"

# 重置信号处理
trap - SIGINT SIGTERM

echo -e "\n=== 系统资源限制 ==="
echo "打开文件数限制:"
ulimit -n
echo "进程数限制:"
ulimit -u

运行结果:

复制代码
=== 进程信息 ===
当前Shell的PID: 12345
父进程PID: 12340
当前用户: user

=== 运行进程 ===
在后台运行sleep命令:
sleep进程PID: 12346

运行多个后台进程:
启动进程 1, PID: 12347
启动进程 2, PID: 12348
启动进程 3, PID: 12349

=== 进程列表 ===
当前用户进程:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user     12345  0.0  0.0  12345  6789 pts/0    S    10:30   0:00 bash
user     12346  0.0  0.0  12346  1234 pts/0    S    10:30   0:00 sleep 10

进程树:
bash(12345)─┬─sleep(12346)
            ├─sleep(12347)
            ├─sleep(12348)
            └─sleep(12349)

=== 进程监控 ===
CPU使用率最高的进程:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user     12350  5.0  0.0  12350  1234 pts/0    R    10:30   0:00 ps aux --sort=-%cpu

内存使用率最高的进程:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user     12351  0.0  0.1 123456 12345 pts/0    S    10:30   0:00 some_process

=== 进程控制 ===
等待sleep进程完成:
sleep进程已完成

启动一个长时间运行的进程:
运行ping命令 (5秒后停止)...
停止ping进程 (PID: 12352)
进程被终止

=== 作业控制 ===
启动两个作业:
作业1 (sleep 20): PID=12353
作业2 (sleep 30): PID=12354

作业列表:
[1]-  运行中               sleep 20 &
[2]+  运行中               sleep 30 &

将作业2放到前台:
[2]+  继续               sleep 30

将作业2放回后台:
[2]+ sleep 30 &

终止所有sleep进程:
已终止所有sleep进程

=== 进程间通信 ===
创建命名管道:
通过管道发送数据...
Hello from process 1

=== 信号处理 ===
按Ctrl+C发送SIGINT信号
等待5秒...
^C收到SIGINT信号

=== 系统资源限制 ===
打开文件数限制: 1024
进程数限制: 12345

由于篇幅限制,这里只展示了前14天的示例。如果你需要完整的30天示例,我可以继续提供剩余的内容。每个示例都包含详细的注释和预期的运行结果,帮助你逐步掌握Shell脚本编程。

相关推荐
晚霞的不甘1 小时前
实战深研:构建高可靠、低延迟的 Flutter + OpenHarmony 智慧教育互动平台(支持离线教学、多端协同与国产化适配)
前端·javascript·flutter
董世昌411 小时前
前端跨域问题:原理、8 种解决方案与实战避坑指南
开发语言·前端·javascript
吃炸鸡的前端1 小时前
Vite创建react项目
前端·react.js·前端框架
IT_陈寒1 小时前
Redis性能提升40%!我用这5个冷门但高效的配置优化了千万级QPS应用
前端·人工智能·后端
GISer_Jing1 小时前
SSE Conf 大会分享——AI Native 3D开发革命,让创意不再被技术门槛阻挡(推荐!!!)
前端·人工智能·3d·信息可视化
克喵的水银蛇1 小时前
Flutter 通用网络图片封装实战:带占位 / 错误 / 缓存的 CachedImageWidget
开发语言·前端·javascript
kong@react1 小时前
springbpoot项目,富文本,xss脚本攻击防护,jsoup
java·前端·spring boot·xss
涵涵(互关)2 小时前
后端返回的id到前端接收时,id改变了
前端·状态模式
拾忆,想起2 小时前
Dubbo灰度发布完全指南:从精准引流到全链路灰度
前端·微服务·架构·dubbo·safari