【上級運用保守知識】シェルプログラミング演習34問と解答(基礎から実戦まで:基礎+計算+判断+ループ+制御・配列+応用実戦)

この記事では、シェルの文法演習のほとんどをカバーしています。実践的な演習を 1 つずつ使用して、シェルの学習を定着させます。早速、直接始めてみましょう。

1. 基本

演習 1: 時刻に応じてファイル「2018-05-22.log」を生成し、毎日のディスク使用状況を日付に対応するファイルに書き込みます

[root@Shell test]# cat disk_status_backup.sh
#!/bin/bash
name=`date +%F`
/bin/df -h > /tmp/"$name".log
[root@Shell test]# sh disk_status_backup.sh
[root@Shell test]# cat /tmp/2023-05-17.log 
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        476M     0  476M   0% /dev
tmpfs           487M     0  487M   0% /dev/shm
tmpfs           487M   14M  473M   3% /run
tmpfs           487M     0  487M   0% /sys/fs/cgroup
/dev/sda3        19G  2.0G   17G  11% /
/dev/sda1       197M  110M   88M  56% /boot
tmpfs            98M     0   98M   0% /run/user/0
[root@Shell test]# crontab -l
59 23 * * * sh /server/scripts/test/disk_status_backup.sh

演習 2: Nginx ログ内の各 IP のアクセス数をカウントします。ログの形式は次のとおりです。

192.168.56.1 - - [21/May/2018:20:44:06 -0400] "GET /index.html HTTP/1.0" 404 169 "-" "ApacheBench/2.3" "-"/code/index.html

[root@Shell test]# cat count_nginx_ip.sh
#!/bin/bash
cat /var/log/nginx/access.log-20230506|awk '{print $1}'|sort -rn|uniq -c
[root@Shell test]# sh count_nginx_ip.sh
    207 172.16.1.5

演習 3: Linux システム内のすべてのプロセスが占有するメモリのサイズを計算するスクリプトを作成します。
%MEM 列は、プロセスが占有する物理メモリの割合です。この値を見ると、プロセスによって使用されている物理メモリの割合を確認できます。
VSZ (Virtual Memory Size) は仮想メモリのサイズで、プロセスが使用する仮想メモリ空​​間のサイズを示します。
RSS (Resident Set Size) は、プロセスによって実際に使用される物理メモリ サイズ、つまり占有メモリ量 (KB 単位) です。
RSSの合計を求めます

[root@Shell test]# cat process_occupies_memory_size.sh
#!/bin/bash
ps axu|awk 'NR!=1{print $6}'|grep -v ^0$|awk '{sum+= $1}END{print sum}'
[root@Shell test]# sh process_occupies_memory_size.sh
2038676

演習 4: /backup の下に 10 個の .txt ファイルを作成し、/backup ディレクトリ内で .txt のサフィックスを持つすべてのファイルを検索し、
バッチで txt を txt.bak に変更し、すべての .bak ファイルを 123.tar.gz にパックして圧縮します。バッチ復元ファイルの名前、追加された .bak を削除します

[root@Shell test]# cat file_handle.sh
#!/bin/bash
for i in `ls /backup`
do
	cp /backup/"$i" /backup/"$i".bak
done
tar zcvf /backup/123.tar.gz /backup/*.txt.bak &> /dev/null
rm -rf /backup/*.txt.bak
[root@Shell test]# sh file_handle.sh
[root@Shell test]# ls /backup/
10.txt      1.txt  3.txt  5.txt  7.txt  9.txt
123.tar.gz  2.txt  4.txt  6.txt  8.txt
[root@Shell test]# tar tf /backup/123.tar.gz 
backup/10.txt.bak
backup/1.txt.bak
backup/2.txt.bak
backup/3.txt.bak
backup/4.txt.bak
backup/5.txt.bak
backup/6.txt.bak
backup/7.txt.bak
backup/8.txt.bak
backup/9.txt.bak

2. 計算

演習 1: 2 つの整数を入力し、これら 2 つの整数の加算、減算、乗算、除算、および剰余の結果を計算します。

[root@Shell test]# cat jisuan.sh
#/bin/bash
num1=$1
num2=$2

echo "两数相加为:$num1 + $num2 = $(awk "BEGIN{print $num1+$num2}")"
echo "两数相减为:$num1 - $num2 = $(awk "BEGIN{print $num1-$num2}")"
echo "两数相乘为:$num1 * $num2 = $(awk "BEGIN{print $num1*$num2}")"
echo "两数相除为:$num1 / $num2 = $(awk "BEGIN{print $num1/$num2}")"
echo "两数求余为:$num1 % $num2 = $(awk "BEGIN{print $num1%$num2}")"
[root@Shell test]# sh jisuan.sh 9 3
两数相加为:9 + 3 = 12
两数相减为:9 - 3 = 6
两数相乘为:9 * 3 = 27
两数相除为:9 / 3 = 3
两数求余为:9 % 3 = 0

演習 2: テキスト文書の最初の 5 行にある文字を含む行を削除し、6 行目から 10 行目の文字をすべて削除します。

[root@Shell test]# cat delete.sh
#!/bin/bash

# 指定待处理的文本文档路径
file_path="your_file_path.txt"

# 临时文件路径
temp_file="temp.txt"

# 删除前五行中包含字母的行
sed '1,5 { /[a-zA-Z]/d }' "$file_path" > "$temp_file"

# 删除6到10行中的所有字母
sed '6,10 s/[a-zA-Z]//g' "$temp_file" > "$file_path"

# 删除临时文件
rm "$temp_file"

練習問題 3: 次の文の 3 文字未満の単語を出力してください、私は koten、私は 18 です

[root@Shell test]# cat print.sh
#!/bin/bash

sentence="I am koten I am 18"

echo "$sentence" | awk '{ for(i=1; i<=NF; i++) { if (length($i) < 3) print $i } }'

演習 4: Linux システムにカスタム ユーザー (通常のユーザー) が存在するかどうかを確認するシェルを作成します。存在する場合、何人いますか?

[root@Shell test]# cat user.sh 
#!/bin/bash

# 获取系统中普通用户的数量
user_count=$(awk -F: '$3>=1000 && $1!="nobody" {print $1}' /etc/passwd | wc -l)

if [ $user_count -gt 0 ]; then
    echo "系统中存在 $user_count 个自定义普通用户。"
else
    echo "系统中没有自定义普通用户。"
fi

演習 5: シェル スクリプトを作成して、最もよく使用するコマンドを確認し、最もよく使用されるコマンドのトップ 10 をリストします。

[root@Shell test]# cat history_cmd.sh
#!/bin/bash

# 指定要统计的shell历史文件路径
history_file=~/.bash_history

# 统计命令使用频率,并获取前10个最常用的命令
top_commands=$(cat "$history_file" | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10)

echo "您使用最多的命令 Top 10:"
echo "$top_commands"

演習 6: 100 以内の 3 で割り切れるすべての数値の合計を計算するスクリプトを作成します。

[root@Shell test]# cat 3.sh 
#!/bin/bash

sum=0

# 循环遍历1到100之间的数字
for ((num=1; num<=100; num++))
do
    # 判断数字是否能被3整除
    if [ $((num % 3)) -eq 0 ]; then
        sum=$((sum + num))
    fi
done

echo "100以内所有能被3整除的数字的和为:$sum"

3. 判断

演習 1: 次の条件式を if 条件文として記述します
[ -f /etc/hosts ] && echo !

[root@Shell test]# cat if.sh 
#!/bin/bash

if [ -f /etc/hosts ]; then
    echo "!"
fi

演習 2: 10.0.0.0/24 ネットワーク内の現在のオンライン ユーザーの IP の判断を実現するスクリプトを作成します。

[root@Shell test]# cat ping.sh
#!/bin/bash

network="10.0.0"

# 循环遍历IP地址范围内的所有地址
for ((i=1; i<=255; i++))
do
    ip="${network}.${i}"
    
    # 使用ping命令检查IP地址是否在线
    ping -c 1 -w 1 "$ip" > /dev/null 2>&1
    
    # 检查ping命令的返回值,如果为0则表示IP地址在线
    if [ $? -eq 0 ]; then
        echo "IP地址 $ip 在线"
    fi
done

演習 3: シェルを使用して次のコンテンツを処理し、単語の出現頻度で降順、文字の出現頻度で降順に並べ替えます。
Squid プロジェクトは、ユーザーの Squid インストールの設計、実装、サポートを支援するための多数のリソースを提供します。詳細については、ドキュメントとサポートのセクションを参照してください。

[root@Shell test]# cat sort.sh
#!/bin/bash

content="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 information."

# 按单词出现频率降序排序
word_frequency=$(echo "$content" | awk '{ for(i=1; i<=NF; i++) { count[$i]++ } } END { for(word in count) { print count[word], word } }' | sort -rn)

echo "按单词出现频率降序排序:"
echo "$word_frequency"

echo

# 按字母出现频率降序排序
letter_frequency=$(echo "$content" | grep -o . | grep -v '[. ]' | sort | uniq -c | sort -rn)

echo "按字母出现频率降序排序:"
echo "$letter_frequency"

演習 4: ps aux を使用してシステム プロセスを表示し、100 個の test.sh スクリプトが実行されていることを確認します。すべての test.sh を強制終了する方法

[root@Shell test]# cat kill.sh
ps aux | grep test.sh | awk '{print $2}' | xargs kill

演習 5: 数字推測スクリプトを作成します。ユーザーが入力した数字がプリセット番号と同じ場合 (0 ~ 100 の数字がランダムに生成されます)、終了します。そうでない場合は、ユーザーに入力を続けさせ、ユーザーに数字を入力するよう促します。プリセット番号より大きいか小さい

この記事をクリックしてコードを表示します

演習 6: シェルを使用して、テキスト文書内の数字が 1 つだけ含まれる行を印刷する

[root@Shell test]# cat print_num.sh
#!/bin/bash

filename="your_text_file.txt"

while read -r line; do
  # 使用正则表达式匹配只有一个数字的行
  if [[ $line =\~ ^[0-9]+$ ]]; then
    echo "$line"
  fi
done < "$filename"

演習 7: シェル スクリプトを作成し、curl コマンドによって返されるステータス コードを通じて、訪問した Web サイトが正常かどうかを判断します。たとえば、現在のステータス コードは 200 で、これは正常とみなされます。

[root@Shell test]# cat curl.sh
#!/bin/bash

# 设置要访问的网站URL
website="https://www.baidu.com"

# 发送GET请求并获取状态码
status_code=$(curl -s -o /dev/null -w "%{http_code}" "$website")

# 判断状态码是否为200
if [ "$status_code" -eq 200 ]; then
  echo "Website is accessible!"
else
  echo "Website is not accessible! Status code: $status_code"
fi

4. サイクル

演習 1: while ループを使用して 1 から 100 を加算する

[root@Shell test]# cat add.sh
#!/bin/bash

sum=0
counter=1

while [ $counter -le 100 ]
do
    sum=$((sum + counter))
    counter=$((counter + 1))
done

echo "1加到100的和为: $sum"

演習 2: ディスクと現在の使用状況を確認し、使用率が 80% を超えている場合は結果を /var/log/disk.err に出力します

[root@Shell test]# cat disk.sh
#!/bin/bash

# 设置磁盘使用率阈值
threshold=80

# 执行df命令获取磁盘使用状态,并使用awk过滤出使用率超过阈值的行
df_output=$(df -h | awk '$5 > threshold')

# 检查是否有超过阈值的行
if [ -n "$df_output" ]; then
  echo "$df_output" >> /var/log/disk.err
  echo "Disk usage exceeded the threshold and logged to /var/log/disk.err"
else
  echo "Disk usage is within the threshold"
fi

演習 3: スクリプトは 10 人のユーザーを一括で作成し、パスワードは一律 123 です。ユーザーの入力が数字であるか、入力された名前が空であるかを判断する必要があります

[root@Shell test]# cat useradd.sh
#!/bin/bash

count=1

while [ $count -le 10 ]
do
    echo "请输入第 $count 个用户的名字:"
    read username
    
    # 判断用户名是否为空
    if [ -z "$username" ]; then
        echo "用户名不能为空,请重新输入!"
        continue
    fi
    
    echo "请输入第 $count 个用户的密码:"
    read password
    
    # 判断密码是否为数字
    if ! [[ $password =\~ ^[0-9]+$ ]]; then
        echo "密码必须为数字,请重新输入!"
        continue
    fi
    
    # 创建用户并设置密码
    sudo useradd -m $username
    echo "$username:$password" | sudo chpasswd
    
    count=$((count + 1))
done

演習 4: case ステートメントを使用して nginx 起動スクリプトを作成する

この記事をクリックしてコードを表示します

演習 5: 抽選プログラム。スクリプトを実行した後、行きたい生徒は英語のフルネームを入力し、01 から 99 までの乱数を生成します。数字が大きいほど、プロジェクトの実践に参加する可能性が高くなります。数字は、以前に捕らえられたものは次回は使用できません 同じ番号が再び表示されます; 最初の生徒が名前を入力すると、画面に情報が出力され、名前と番号がファイルに記録されます プログラムは終了できず、他の生徒が入力するのを待ち続けます入力。

この記事をクリックしてコードを表示します

演習 6: 次のようにメニューを出力し、loop plus case ステートメントを使用して、ユーザーが入力したメニュー オプションの結果を出力します。 h コマンド ヘルプの表示
f
ログイン情報の表示
d ディスク マウントの表示
m メモリ使用量の確認
u システム負荷の確認
qプログラムを終了する

この記事をクリックしてコードを表示します

5、コントロールとアレイ

演習 1: 0 ~ 100 の乱数を生成し、1000 を超えるまで加算し、加算結果を出力します。

[root@Shell test]# cat addnum.sh
#!/bin/bash

sum=0

while [ $sum -le 1000 ]
do
    # 生成0-100之间的随机数
    random_number=$((RANDOM % 101))
    sum=$((sum + random_number))
done

echo "和大于1000的结果为: $sum"

演習 2: 0 ~ 100 の乱数を生成し、1000 を超えるまで合計し、最後の乱数が 3 で割り切れるかどうかを判定します。

[root@Shell test]# cat 3.sh
#!/bin/bash

sum=0
last_random_number=0

while [ $sum -le 1000 ]
do
    # 生成0-100之间的随机数
    random_number=$((RANDOM % 101))
    sum=$((sum + random_number))
    last_random_number=$random_number
done

echo "和大于1000的结果为: $sum"

# 判断最后一个随机数字是否能被3整除
if [ $((last_random_number % 3)) -eq 0 ]; then
    echo "最后一个随机数字 $last_random_number 能被3整除"
else
    echo "最后一个随机数字 $last_random_number 不能被3整除"
fi

演習 3: /tmp/ ディレクトリに 4K を超えるファイルがあるかどうかを確認し、存在する場合はファイルのサイズと作成時刻を出力します。

[root@Shell test]# cat 4K.sh
#!/bin/bash

path="/tmp/"

# 使用find命令查找/tmp/目录下大于4K的文件,并使用-printf选项输出文件大小和创建时间
find "$path" -type f -size +4k -printf "文件:%p,大小:%s字节,创建时间:%TY-%Tm-%Td %TH:%TM:%TS\n"

演習 4: 配列 array=(1 2 3 4 5 6) スクリプトを使用して各要素を出力し、1 行に 1 つの要素を表示します

[root@Shell test]# cat array.sh
#!/bin/bash

array=(1 2 3 4 5 6)

# 使用for循环遍历数组
for element in "${array[@]}"
do
    echo "$element"
done

演習 5: 配列を使用して、「I am koten ようこそ、故郷へ」の 6 文字以上の単語を特定します。

[root@Shell test]# cat array_6.sh
#!/bin/bash

sentence="I am koten welcome to my hometown"
words=($sentence)

# 使用for循环遍历数组中的每个单词
for word in "${words[@]}"
do
    # 统计单词中的字母数
    length=${#word}

    # 判断字母数是否大于6
    if [ $length -gt 6 ]; then
        echo "$word"
    fi
done

6. 実戦での進歩

演習 1: サーバー内の重要なファイルが変更されているかどうかを検出し、変更された場合は警察に通報します (フィンガープリントを使用)

[root@Shell test]# cat fingerprint.sh
#!/bin/bash

# 定义重要文件的路径和对应的指纹
declare -A important_files=(
    ["/path/to/file1"]="fingerprint1"
    ["/path/to/file2"]="fingerprint2"
    ["/path/to/file3"]="fingerprint3"
)

# 检测文件是否被修改
for file in "${!important_files[@]}"; do
    # 计算当前文件的指纹
    current_fingerprint=$(md5sum "$file" | awk '{print $1}')

    # 比较当前指纹和预设的指纹
    if [[ "$current_fingerprint" != "${important_files[$file]}" ]]; then
        echo "警报!文件 $file 已被修改!"
        # 在此处添加触发报警的操作,比如发送邮件或短信通知管理员
    fi
done

演習 2: nginx ログ内の最もアクセスの多い 10 の IP によって使用されるトラフィック合成を計算する

[root@Shell test]# cat ip.sh
#!/bin/bash

logfile="access.log"

# 使用awk命令提取日志中的IP和流量信息,并按照IP统计流量总和
ip_traffic=$(awk '{ ip[$1] += $10 } END { for(i in ip) print i, ip[i] }' "$logfile")

# 使用sort命令对流量进行降序排序
sorted_ip_traffic=$(echo "$ip_traffic" | sort -k2 -rn)

# 使用head命令获取前10个IP和对应的流量
top_10_ip_traffic=$(echo "$sorted_ip_traffic" | head -n 10)

# 输出结果
echo "访问最多的10个IP使用的流量综合:"
echo "$top_10_ip_traffic"

演習 3: DOS 攻撃を防止し、nginx ログを確認し、特定の IP の PV が短期間で大きすぎる場合は、ファイアウォールを使用して禁止します。

[root@Shell test]# cat iptables.sh
#!/bin/bash

logfile="access.log"
threshold=100  # 设置阈值,表示短时间内的页面访问量上限
ban_time=60    # 设置禁用时间,单位为秒

# 使用awk命令提取日志中的IP信息,并统计每个IP的页面访问量
ip_pv=$(awk '{ ip[$1]++ } END { for(i in ip) print i, ip[i] }' "$logfile")

# 使用while循环遍历PV统计结果
while IFS= read -r line; do
    ip=$(echo "$line" | awk '{print $1}')
    pv=$(echo "$line" | awk '{print $2}')

    # 判断页面访问量是否超过阈值
    if [ "$pv" -gt "$threshold" ]; then
        echo "警报!IP $ip 的短时间内页面访问量过大!"

        # 使用防火墙命令禁用IP
        iptables -A INPUT -s "$ip" -j DROP

        # 等待一段时间后解禁IP
        sleep "$ban_time"
        iptables -D INPUT -s "$ip" -j DROP
    fi
done <<< "$ip_pv"

演習 4: リアルタイム監視サーバーの CPU 使用率が 80% を超え、ディスク使用率が 80% を超え、メモリ使用率が 80% を超え、アラームが発生する

[root@Shell test]# cat cpu_disk.sh
#!/bin/bash

# 配置监控阈值
cpu_threshold=80
disk_threshold=80
memory_threshold=80

# 检查CPU使用率
check_cpu() {
    cpu_usage=$(sar -u 1 1 | grep Average | awk '{print 100 - $NF}')

    if [ "$cpu_usage" -gt "$cpu_threshold" ]; then
        echo "警报!CPU使用率超过 $cpu_threshold%!"
        # 在此处添加触发报警的操作,比如发送邮件通知管理员
    fi
}

# 检查磁盘使用率
check_disk() {
    disk_usage=$(df -h | awk '/\/$/ {print $5}' | sed 's/%//')

    if [ "$disk_usage" -gt "$disk_threshold" ]; then
        echo "警报!磁盘使用率超过 $disk_threshold%!"
        # 在此处添加触发报警的操作,比如发送邮件通知管理员
    fi
}

# 检查内存使用率
check_memory() {
    memory_usage=$(free | awk '/Mem/ {printf "%.2f", $3/$2 * 100}')

    if (( $(echo "$memory_usage > $memory_threshold" | bc -l) )); then
        echo "警报!内存使用率超过 $memory_threshold%!"
        # 在此处添加触发报警的操作,比如发送邮件通知管理员
    fi
}

# 持续监控
while true; do
    check_cpu
    check_disk
    check_memory
    sleep 5
done

演習 5: バイナリを使用して nginx をインストールし、スクリプトを再実行可能にする必要がある

[root@Shell test]# cat nginx.sh
#!/bin/bash

nginx_version="1.18.0"  # 设置nginx版本号
nginx_install_dir="/usr/local/nginx"  # 设置nginx安装目录

# 下载nginx源码包
wget http://nginx.org/download/nginx-$nginx_version.tar.gz

# 解压源码包
tar -zxvf nginx-$nginx_version.tar.gz

# 进入解压后的目录
cd nginx-$nginx_version

# 配置编译参数
./configure --prefix=$nginx_install_dir

# 编译和安装
make && make install

# 清理临时文件
cd ..
rm -rf nginx-$nginx_version
rm nginx-$nginx_version.tar.gz

演習 6: データベースのサブデータベースとサブテーブルを /tmp にバックアップします。

[root@Shell test]# cat mysql.sh
#!/bin/bash

# 定义数据库连接信息
host=localhost
port=3306
user=root
password=123456

# 定义要备份的数据库和表
db_list=(db1 db2)
table_list=(table1 table2 table3)

# 遍历数据库
for db in ${db_list[@]}; do
  # 遍历表
  for table in ${table_list[@]}; do
    # 构建备份文件名
    bak_file=/tmp/${db}_${table}.sql
    
    # 执行备份命令
    mysqldump -h$host -P$port -u$user -p$password $db $table > $bak_file
    
    # 检查备份是否成功
    if [ $? -eq 0 ]; then
      echo "备份 $db.$table 成功"
    else
      echo "备份 $db.$table 失败"
    fi
  done
done

運用保守歴10年、ドライグッズの運用保守を続けているkotenです。

おすすめ

転載: blog.csdn.net/qq_37510195/article/details/131631010