02 万丈高楼平地起 - Bash 的基础语法 -1
第一个 bash 脚本
bash
cd ~ # 切换到用户主目录
vim test.sh # 创建并打开 test.sh 文件
# 在 test.sh 文件中输入以下内容:
#!/bin/bash
echo "hello" > today.log
# 按 Esc 键,输入 :wq,然后按回车。
:wq # 保存并退出
bash test.sh # 直接用 bash 执行脚本
# 或者
chmod +x test.sh # 赋予执行权限
./test.sh # 通过相对路径执行脚本
cat today.log # 查看 today.log 文件内容#!/bin/bash:这是一个 shebang,用于指定解释器,告诉系统用 bash 来解释这个脚本。echo "hello" > today.log:将字符串"hello"重定向输出到today.log文件中。如果today.log文件不存在,则会创建它;如果存在,则会覆盖文件内容。
bash 脚本顺序执行
bash
#!/bin/bash
echo "line one" > today.log
echo "line two" >> today.log
echo "line three" >> today.log# !/bin/bash应为#!/bin/bash,这叫 Shebang,用于指定解释器。>表示覆盖写入文件。>>表示追加写入文件。
bash 注释
- 在
bash中,单行注释使用#符号,所有在#之后的内容都会被视为注释。 bash不支持多行注释,不过可以通过多个#或使用: <<'EOF'模拟多行注释。- 注释的用途
- 描述代码功能:解释脚本或特定命令的作用。
- 调试代码:通过注释掉部分代码来测试脚本的不同部分。
- 提供信息:记录作者、修改日期或注意事项等。
bash
➜ 0902 git:(main) cat bash_comment.sh
#!/bin/bash
# 作者: wwvl
# 这个脚本用于演示如何在 Bash 中使用注释
# 打印欢迎信息
echo "欢迎使用 Bash 脚本!"
# 计算两个数的和
num1=5
num2=10
# 计算并打印结果
result=$((num1 + num2)) # 使用算术表达式计算和
echo "The result is: $result"
# : <<'EOF' 告诉 Bash 忽略从 EOF 开始到结束标记 EOF 之间的内容。EOF 可以替换为其他任意文本,如 END
: <<'EOF'
以下部分代码是未完成的功能
echo "This code is not ready yet"
EOF
➜ 0902 git:(main) bash bash_comment.sh
欢迎使用 Bash 脚本!
The result is: 15总结
- 单行注释:使用
#。 - 多行注释:用多个
#或使用: <<'EOF'等技巧。 - 注释是编写易读代码的好习惯,可以帮助自己和他人理解代码逻辑。
bash 参数
bash
#!/bin/bash
# 获取当前 CPU 空闲百分比
# idle_percent=`top -n 1 | grep "%Cpu" | awk '{print $8}'` # 使用 `` 执行命令
idle_percent=$(top -n 1 | grep "%Cpu" | awk '{print $8}') # 使用 `$()` 执行命令
echo "Idle percent: $idle_percent"
# 设置空闲阈值
idle_thres=75 # 直接赋值
echo "Idle threshold: $idle_thres"
# 计算忙碌的阈值
busy_thres=$((100 - idle_thres)) # 使用 `$(())` 进行数值运算
echo "Busy threshold: $busy_thres"
# 计算忙碌百分比
#busy_percent=`echo "100 - $idle_percent" | bc` # 使用 bc 进行数值运算
busy_percent=$(echo "100 - $idle_percent" | bc)
echo "Busy percent: $busy_percent"命令替换
| 特性 | 反引号 | $() |
|---|---|---|
| 语法和可读性 | 语法:command | 语法:$(command) |
| 嵌套使用 | 嵌套使用时需要转义内部反引号,不易读 | 嵌套使用时不需要转义,更易读 |
| 反引号 | 需要转义内部反引号,复杂且难以维护 | 不需要转义,简洁且易读 |
| 错误处理 | 命令失败时不会立即终止脚本 | 命令失败时不会立即终止脚本,但可以通过 set -e 强制终止 |
| 兼容性 | 在较早的 Bourne Shell (sh) 中存在 | 是 POSIX 标准的一部分,现代 Bash 和大多数 POSIX 兼容的 shell 中支持 |
| 使用建议 | 推荐使用 $(),因为它更易读、更易维护,并且在嵌套使用时不会导致语法混淆 | 推荐使用 $(),因为它更易读、更易维护,并且在嵌套使用时不会导致语法混淆 |
在 Linux 中,``(反引号)和 $()都用于在bash 中执行命令,并将命令的输出结果作为值返回。但它们之间有一些关键的区别:
可读性和嵌套
反引号 ``:
可读性较差,尤其是在嵌套的命令中。
如果需要嵌套执行命令,使用反引号会显得复杂且容易出错。
bashresult=`command1 \`command2\`` # 这种嵌套的结构看起来复杂且难以理解
$():
可读性较好,尤其是嵌套时非常清晰。
可以轻松嵌套其他命令,不容易混淆。
bashresult=$(command1 $(command2)) # 这个结构明显更清晰、更容易阅读
兼容性
- 反引号:是较早的语法,兼容性更广,适用于非常老的 shell(比如早期的
sh)。 - $():是现代的语法,几乎所有的现代 shell(如
bash、zsh)都支持,但在非常旧的 shell 中可能不被支持。
处理转义字符
反引号:反引号内部如果需要处理转义字符,如反斜杠
\,容易出错。bashresult=`echo "This is a backtick: \`"` # 处理转义字符时,代码可读性会下降$():
$()更好地处理复杂的字符串和转义字符。比如:bashresult=$(echo "This is a backtick: `") # $() 能更清晰地处理这些复杂的符号,避免了繁琐的转义
行内换行支持
反引号:反引号不支持在命令中换行,如果命令过长或分多行书写,需要结合
\来续行。bashresult=`command1 \ command2`$():
$()支持命令内部换行,书写更为灵活且易读。bashresult=$( command1 command2 )
推荐使用 `$()`
尽管反引号语法依然有效并且可以在大多数情况下正常工作,但现代 bash 和其他 shell 更推荐使用 $(),因为它在嵌套命令、可读性、灵活性方面具有更好的优势。
总结
- 反引号:旧的语法,兼容性强,但可读性差,嵌套时不方便。
- $():现代语法,推荐使用,支持嵌套、易于阅读,能更好地处理复杂的转义字符。
因此,除非需要兼容非常老的 shell 环境,一般建议使用 $() 语法。
数值运算
在 Linux bash 中,原生的 bash 只支持整数的数值运算。
| 方法 | 说明 | 是否支持浮点数 |
|---|---|---|
let | bash 内置命令 | 不支持 |
expr | 独立命令 | 不支持 |
$(( )) | bash 算术扩展 | 不支持 |
bc | 精确计算工具 | 支持 |
awk | 强大的文本处理工具 | 支持 |
let 命令
let是bash内建命令,可以用于执行基本的算术运算。let命令用于执行算术运算并将结果赋值给变量。let默认支持整数运算,不支持小数。
bash
let result=1+2
echo $result # 输出 3
# 可以省略等号两边的空格
let "result = 1 + 2"
echo $result # 输出 3expr 命令
expr命令可以用于执行整数算术运算。它更像是一个独立的工具,而不是bash内置命令。- 因为
*在 Bash 中有特殊的含义(表示通配符),所以乘法需要使用反斜杠\*来转义星号。 expr也不支持浮点数运算。
bash
result=$(expr 1 + 2)
echo $result # 输出 3
# 乘法运算需要使用反斜杠 \* 转义
result=$(expr 3 \* 2)
echo $result # 输出 6$(( )) 算术扩展
- 这是
bash中推荐的进行整数运算的方式,支持更复杂的表达式。 - 支持各种运算符:加 (
+) 减 (-) 乘 (*) 除 (/) 取模 (%)。
bash
result=$((1 + 2))
echo $result # 输出 3
result=$((10 / 3))
echo $result # 输出 3bc 命令
bash本身不支持浮点数运算,如果你需要进行小数计算,可以使用bc命令,这是一个用于精确数值计算的工具- CentOS 系统安装
bc命令:sudo dnf install -y bc。
bash
# 浮点数运算
result=$(echo "scale=2; 10 / 3" | bc) # scale=2 表示保留两位小数
echo $result # 输出 3.33
result=$(echo "1.5 + 2.7" | bc)
echo $result # 输出 4.2
result=$(echo "3.14 * 2" | bc)
echo $result # 输出 6.28
# 进行指数运算
result=$(echo "2^3" | bc)
echo $result # 输出 8awk 命令
awk是 Linux 的强大文本处理工具之一,也可以用来做数值运算。
bash
# 浮点数运算
result=$(awk 'BEGIN {print 1.5 + 2.7}')
echo $result # 输出 4.2
# 常见运算
result=$(awk 'BEGIN {print 10 / 3}')
echo $result # 输出 3.33333
result=$(awk 'BEGIN {print 3 * 4}')
echo $result # 输出 12总结
- 整数运算:使用
let、expr、$(( ))进行基本的整数运算。 - 浮点数运算:使用
bc或awk来处理浮点数和更复杂的计算。
bash 脚本传参
- 在
bash脚本中,可以通过命令行传递参数给脚本。 - 传递的参数会作为特殊的变量存储,通常用
$1,$2,$3等来表示对应位置的参数,$0表示脚本的名称。
| 特殊变量 | 说明 | 示例 |
|---|---|---|
$0 | 脚本名称 | ./script.sh 输出 ./script.sh |
$1, $2, ... | 位置参数,依次代表传递给脚本的第 1、2、3... 个参数 | ./script.sh arg1 arg2, $1 是 arg1 |
$# | 传递给脚本的参数个数 | ./script.sh arg1 arg2 输出 2 |
$@ | 传递给脚本的所有参数(每个参数独立处理,保持原样) | "$@" 输出 arg1 arg2 arg3 |
$* | 传递给脚本的所有参数(作为单个字符串) | "$*" 输出 arg1 arg2 arg3 |
脚本传参
bash
➜ 0902 git:(main) cat args_demo_various_methods.sh
#!/bin/bash
# 脚本名称
echo "Script name: $0"
# 第一个参数
echo "First argument: $1"
# 第二个参数
echo "Second argument: $2"
# 所有参数作为一个整体字符串
echo "All arguments (\$*): $*"
# 所有参数作为独立字符串
echo "All arguments (\$@): $@"
# 参数个数
echo "Total number of arguments: $#"
➜ 0902 git:(main) bash args_demo_various_methods.sh arg1 arg2 arg3
Script name: args_demo_various_methods.sh
First argument: arg1
Second argument: arg2
All arguments ($*): arg1 arg2 arg3
All arguments ($@): arg1 arg2 arg3
Total number of arguments: 3bash
➜ 0902 git:(main) cat args_sum_two_numbers.sh
#!/bin/bash
# 检查参数个数
if [ "$#" -ne 2 ]; then
echo "Usage: bash $0 num1 num2. (The script needs two parameters)"
exit 1
fi
# 计算和
sum=$(($1 + $2))
# 输出结果
echo "The sum of $1 and $2 is: $sum"
➜ 0902 git:(main) bash args_sum_two_numbers.sh 66 88 99
Usage: bash args_sum_two_numbers.sh num1 num2. (The script needs two parameters)
➜ 0902 git:(main) bash args_sum_two_numbers.sh 66
Usage: bash args_sum_two_numbers.sh num1 num2. (The script needs two parameters)
➜ 0902 git:(main) bash args_sum_two_numbers.sh 66 88
The sum of 66 and 88 is: 154处理多个参数
bash
➜ 0902 git:(main) cat args_iteration_for_and_while.sh
#!/bin/bash
# 使用 for 循环遍历所有参数
for arg in "$@"; do
echo "Argument: $arg"
done
# 使用 while 循环遍历所有参数
index=0
while [ $index -lt $# ]; do
echo "Argument: $1"
shift
index=$((index + 1))
done
➜ 0902 git:(main) bash args_iteration_for_and_while.sh one two three
Argument: one
Argument: two
Argument: three
Argument: one
Argument: two"$@" 和 "$*" 的区别
| 变量 | 说明 | 示例 |
|---|---|---|
"$@" | 每个参数作为独立字符串,常用于遍历参数 | "arg 1" "arg 2" "arg 3" 输出为: arg 1, arg 2, arg 3 |
"$*" | 所有参数作为一个整体字符串 | "arg 1" "arg 2" "arg 3" 输出为: arg 1 arg 2 arg 3 |
bash
➜ 0902 git:(main) cat args_iteration_with_at_and_star.sh
#!/bin/bash
echo "使用 \$@ 遍历参数:"
index=0
for arg in "$@"; do
echo "参数 $index: $arg"
index=$((index + 1))
done
echo "使用 \$* 遍历参数:"
index=0
for arg in "$*"; do
echo "参数 $index: $arg"
index=$((index + 1))
done
➜ 0902 git:(main) bash args_iteration_with_at_and_star.sh arg1 arg2 arg3
使用 $@ 遍历参数:
参数 0: arg1
参数 1: arg2
参数 2: arg3
使用 $* 遍历参数:
参数 0: arg1 arg2 arg3进程 PID
| 变量 | 含义 | 用途 |
|---|---|---|
$$ | 当前 Shell 进程的 PID | 获取当前 Shell 进程的 PID,用于日志记录、调试及进程控制。 |
$PPID | 当前 Shell 的父进程的 PID | 获取当前 Shell 的父进程 PID,便于了解父子进程关系。 |
$! | 最后一个后台进程的 PID | 获取最后一个后台任务的 PID,用于管理和控制后台进程。 |
$BASHPID | 当前 Bash 子进程的 PID | 获取子进程的 PID,尤其在子进程中使用,与 $$ 返回不同的值。 |
$$ 当前 Shell 进程的 PID
- 含义:
$$返回当前 Shell 进程的 PID(Process ID),即正在执行的 Shell 进程的标识符。 - 用途:
- 常用于脚本中,用于获取运行脚本的 Shell 或 Shell 进程的 PID。
- 在日志记录、调试以及进程控制中,
$$可帮助识别和跟踪当前 Shell 的状态。
bash
echo "当前 Shell 进程的 PID 是: $$"$PPID 当前 Shell 进程的父进程的 PID
- 含义:
$PPID返回当前 Shell 进程的父进程的 PID,即启动当前 Shell 的进程(例如终端进程或另一个 Shell)。 - 用途:用于确定当前 Shell 或脚本是由哪个进程启动的,这对分析父子进程关系非常有帮助,尤其是在复杂的进程间通信或调试环境中。
bash
echo "当前 Shell 的父进程 PID 是: $PPID"$! 最后一个后台进程的 PID
- 含义:
$!返回最后一个放入后台执行的命令的进程 ID(PID)。 - 用途:
- 用于追踪和控制最近一个放入后台的任务,通常配合
&使用,以在后台执行任务。 - 你可以通过
$!来获取该后台进程的 PID,随后进行wait或kill等操作。
- 用于追踪和控制最近一个放入后台的任务,通常配合
bash
sleep 100 &
echo "后台进程的 PID 是: $!"$BASHPID 当前 Bash Shell 的子进程的 PID
- 含义:
$BASHPID返回当前执行的子进程的 PID。 - 用途:
- 类似于
$$,但$$在子进程中仍然返回父 Shell 的 PID,而$BASHPID返回的是当前 Shell 的 PID,即子进程的 ID。 - 在脚本中管理和追踪多个子进程时非常有用,尤其是在并发执行的场景中。
- 类似于
- 实用性:
- 并发任务管理:通过
$!可以轻松管理多个后台进程,wait确保它们按顺序完成。 - 调试进程关系:通过
$$和$PPID了解父子进程关系,有助于追踪复杂的进程层次。 - 后台任务控制:结合
kill等命令,还可以动态控制和终止后台进程。
- 并发任务管理:通过
bash
echo "当前子进程的 PID 是: $BASHPID"bash
➜ 0902 git:(main) ✗ cat manage_background_tasks.sh
#!/bin/bash
# 打印当前 Shell 和父进程信息
# 使用 $$ 和 $PPID 分别打印当前 Shell 及其父进程的 PID,帮助了解进程层级关系
echo "当前 Shell 进程的 PID: $$"
echo "当前 Shell 的父进程 PID: $PPID"
# 启动第一个后台任务
# 通过 sleep 命令创建两个后台任务,并使用 $! 获取它们的 PID 进行追踪
sleep 5 &
pid1=$!
echo "启动了一个后台 sleep 任务,PID: $pid1"
# 启动第二个后台任务
sleep 10 &
pid2=$!
echo "启动了另一个后台 sleep 任务,PID: $pid2"
# 使用 ps 命令列出相关的进程信息
echo "当前进程状态 (使用 ps 命令):"
ps -f --pid $$,$PPID,$pid1,$pid2
# 打印子进程信息
# 使用 $BASHPID 打印当前 Shell 的子进程的 PID,帮助区分子进程与父进程的不同
echo "当前子进程的 PID (使用 \$BASHPID): $BASHPID"
# 等待第一个后台任务完成
# 使用 wait 命令确保脚本在后台任务完成后才退出,确保所有任务都顺利执行完毕
wait $pid1
echo "第一个后台任务完成,PID: $pid1"
# 等待第二个后台任务完成
wait $pid2
echo "第二个后台任务完成,PID: $pid2"
echo "所有后台任务完成,脚本结束"
➜ 0902 git:(main) ✗ bash manage_background_tasks.sh
当前 Shell 进程的 PID: 821768
当前 Shell 的父进程 PID: 809333
启动了一个后台 sleep 任务,PID: 821769
启动了另一个后台 sleep 任务,PID: 821770
当前进程状态 (使用 ps 命令):
UID PID PPID C STIME TTY TIME CMD
root 809333 809330 0 10:06 pts/0 00:00:00 -zsh
root 821768 809333 0 10:20 pts/0 00:00:00 bash manage_background_tasks.sh
root 821769 821768 0 10:20 pts/0 00:00:00 sleep 5
root 821770 821768 0 10:20 pts/0 00:00:00 sleep 10
当前子进程的 PID (使用 $BASHPID): 821768
第一个后台任务完成,PID: 821769
第二个后台任务完成,PID: 821770
所有后台任务完成,脚本结束退出状态码
$?是一个特殊的变量,用于获取上一个命令或脚本的退出状态码(也称为返回值或退出码)。- 退出状态码是一个整数,表示命令或脚本执行的结果。大多数情况下:
- 0 表示成功(命令或脚本执行成功)。
- 非 0 表示失败(命令或脚本执行失败)。不同的非零值可能表示不同类型的错误或问题。
- 每个命令的退出状态码通常都遵循一定的规则:
- 0:成功。
- 1-255:表示各种错误。具体的错误码由不同命令定义,可以通过查阅命令的文档或手册页(
man <command>)获取。
| 退出状态码 | 描述 |
|---|---|
| 0 | 命令成功执行 |
| 1 | 一般性错误(命令执行失败) |
| 2 | 误用 shell 内置命令(语法错误) |
| 127 | 命令未找到(输入了不存在的命令) |
| 126 | 命令不可执行(无执行权限或不存在的程序) |
| 130 | 命令被用户通过 Ctrl+C 中断 |
bash
➜ 0902 git:(main) ls check_file_and_create_directory.sh
check_file_and_create_directory.sh
➜ 0902 git:(main) echo $? # 0 表示成功
0
➜ 0902 git:(main) ls nonexistent_file.txt
ls: cannot access 'nonexistent_file.txt': No such file or directory
➜ 0902 git:(main) echo $? # 2 表示命令未找到
2
➜ 0902 git:(main) ./check_file_and_create_directory.sh
zsh: permission denied: ./check_file_and_create_directory.sh
➜ 0902 git:(main) echo $? # 126 表示命令不可执行
126
➜ 0902 git:(main) liasa
ezsh: command not found: liasa
➜ 0902 git:(main) echo $? # 127 表示命令未找到
127
➜ 0902 git:(main) sleep 10
^C
➜ 0902 git:(main) echo $? # 130 表示命令被用户通过 Ctrl+C 中断
130结合逻辑运算符使用
可以结合逻辑运算符(如 && 和 ||)简化命令和脚本中的控制流,这些运算符会根据命令的退出状态决定是否执行下一个命令。
bash
$ mkdir mydir && echo "Directory created successfully"
# 如果 mkdir 成功执行,则 echo 执行。
$ mkdir existing_dir || echo "Failed to create directory"
# 如果 mkdir 失败(比如目录已经存在),则 echo 执行。bash
➜ 0902 git:(main) cat check_file_and_create_directory.sh
#!/bin/bash
# 尝试列出一个不存在的文件
ls nonexistent_file.txt
# 检查上一个命令的退出状态码
if [ $? -eq 0 ]; then
echo "File exists and listed successfully."
else
echo "Error: File does not exist."
fi
mkdir example_directory
# 再次检查上一个命令的退出状态码
if [ $? -eq 0 ]; then
echo "Directory created successfully."
else
echo "Error: Failed to create directory."
fi
rm -rf example_directory
➜ 0902 git:(main) bash check_file_and_create_directory.sh
ls: cannot access 'nonexistent_file.txt': No such file or directory
Error: File does not exist.
Directory created successfully.$_ 上一个命令的最后一个参数
$_是一个特殊变量,用于保存 前一个命令的最后一个参数 或 前一个命令的整个结果,根据上下文不同有不同的表现。- 这个特殊变量在脚本编写和命令行操作时非常有用,能够帮助你快速引用之前的输入内容。
bash
➜ 0902 git:(main) cat use_dollar_underscore.sh
#!/bin/bash
# 定义颜色
FontColor_Green="\033[32m"
FontColor_Suffix="\033[0m"
# 如果没有提供参数,显示用法说明
if [[ -z "$1" && -z "$2" && -z "$3" ]]; then
echo "Usage: bash $0 <directory> <filename> <content>"
exit 1
fi
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"
echo -e "Last argument: ${FontColor_Green}$_${FontColor_Suffix}\n"
# 如果目录不存在,则创建目录并进入目录
if [ ! -d "$1" ]; then
echo "Creating directory: $1"
mkdir "$1" && cd "$_"
fi
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
# 如果文件不存在,则创建文件
if [ ! -f "$2" ]; then
echo "Creating file: $2"
touch "$2"
fi
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
echo "Writing $3 to $2"
echo "$3" >>"$2"
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
echo "File $2 created with content: $3"
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
echo "File $2 created with content:" "$3"
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
cd ..
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
echo "Removing directory: $1"
rm -rf "$1"
echo -e "Current \$_ is: ${FontColor_Green}$_${FontColor_Suffix}\n"
➜ 0902 git:(main) bash use_dollar_underscore.sh mydir myfile.txt "Hello, World~ Hello, wwvl"
First argument: mydir
Second argument: myfile.txt
Third argument: Hello, World~ Hello, wwvl
Last argument: Third argument: Hello, World~ Hello, wwvl
Creating directory: mydir
Current $_ is: mydir
Creating file: myfile.txt
Current $_ is: myfile.txt
Writing Hello, World~ Hello, wwvl to myfile.txt
Current $_ is: Hello, World~ Hello, wwvl
File myfile.txt created with content: Hello, World~ Hello, wwvl
Current $_ is: File myfile.txt created with content: Hello, World~ Hello, wwvl
File myfile.txt created with content: Hello, World~ Hello, wwvl
Current $_ is: Hello, World~ Hello, wwvl
Current $_ is: ..
Removing directory: mydir
Current $_ is: mydir实验代码
- 使用
top -n 3 -d 1 | grep "Cpu(s)" | awk '{print $8}' | awk '{sum += $1} END {print sum/NR}'获取 CPU 平均使用率- 如果遇见使用率为 100.0 的情况,则需要使用
top -n 3 -d 1 | grep "%Cpu" | awk -F ',' '{print $4}' | awk '{print $(NF-1)}'获取 CPU 平均使用率
- 如果遇见使用率为 100.0 的情况,则需要使用
bc和awk支持浮点数运算,而let,expr和$(())只支持整数运算- 使用
bc计算系统使用率时,scale仅影响除法的结果,不影响加减乘法的结果。所以使用echo "scale=2; (100.00 - $cpu_idle_avg) / 1" | bc计算。 - 使用
awk计算系统使用率时,printf可以保留两位小数
- 使用
- 使用
awk取整:- 使用
awk -F '.' '{print $1}'取整 - 使用
awk '{print int($1)}'取整
- 使用
计算 CPU 使用率
bash
➜ 0902 git:(main) cat cpu_usage_calculator.sh
#! /bin/bash
# 定义颜色变量
GREEN='\033[32m'
RESET='\033[0m'
# 使用 top 命令获取 CPU 使用率,使用 awk 命令计算 idle 的 CPU 使用率平均值
# %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
# top -n 3 -d 1 | grep "Cpu(s)" | awk '{print $8}' | awk '{sum += $1} END {print sum/NR}'
# top -n 3 -d 1 | grep "%Cpu" | awk -F ',' '{print $4}' | awk '{print $(NF-1)}' | awk '{print "第 " NR " 次 idle: " $1; sum+=$1} END {cpu_idle_avg=sum/NR; print "idle 的 CPU 使用率平均值: " cpu_idle_avg}'
cpu_idle=$(top -n 3 -d 1 | grep "%Cpu" | awk -F ',' '{print $4}' | awk '{print $(NF-1)}')
echo "$cpu_idle" | awk '{print "第 " NR " 次 idle: " $1; sum+=$1}'
# cpu_idle_avg=$(top -n 3 -d 1 | grep "%Cpu" | awk -F ',' '{print $4}' | awk '{print $(NF-1)}' | awk '{sum+=$1} END {print sum/NR}')
cpu_idle_avg=$(echo "$cpu_idle" | awk '{sum+=$1} END {print sum/NR}')
echo -e "\n使用 awk 计算的 CPU 使用率平均值 (cpu_idle_avg): ${GREEN}$cpu_idle_avg${RESET}\n"
# 使用 bc 计算系统使用率,并保留两位小数
# cpu_system_rate=$(echo "scale=2; 100.00 - $cpu_idle_avg" | bc) # scale 仅影响除法的结果
cpu_system_rate=$(echo "scale=2; (100.00 - $cpu_idle_avg) / 1" | bc)
echo -e "使用 bc 计算系统使用率 (cpu_system_rate): ${GREEN}$cpu_system_rate${RESET}\n"
# 使用 awk 计算系统使用率,并保留两位小数
cpu_system_rate=$(echo "$cpu_idle_avg" | awk '{printf "%.2f", 100 - $1}')
echo -e "使用 awk 计算系统使用率 (cpu_system_rate): ${GREEN}$cpu_system_rate${RESET}\n"
# 使用 let 计算系统使用率
# 直接计算会报错:syntax error: invalid arithmetic operator (error token is "***")
let cpu_system_rate=100-cpu_idle_avg
# let cpu_idle_avg_int=$(echo $cpu_idle_avg | awk -F '.' '{print $1}')
let cpu_idle_avg_int=$(echo "$cpu_idle_avg" | awk '{print int($1)}')
echo "$cpu_idle_avg" | awk -F '.' '{print "计算的 CPU 使用率平均值 (cpu_idle_avg_int): " $1}'
let cpu_system_rate=100-cpu_idle_avg_int
echo -e "使用 let 计算系统使用率 (cpu_system_rate): ${GREEN}$cpu_system_rate${RESET}\n"
# 使用 expr 计算系统使用率
cpu_system_rate=$(expr 100 - $cpu_idle_avg) # 直接计算会报错:expr: non-integer argument
cpu_system_rate=$(expr 100 - $cpu_idle_avg_int)
echo -e "使用 expr 计算系统使用率 (cpu_system_rate): ${GREEN}$cpu_system_rate${RESET}\n"
# 使用 $(()) 计算系统使用率
cpu_system_rate=$((100 - cpu_idle_avg)) # 直接计算会报错:syntax error: invalid arithmetic operator (error token is "***")
cpu_system_rate=$((100 - cpu_idle_avg_int))
echo -e "使用 \$(()) 计算系统使用率 (cpu_system_rate): ${GREEN}$cpu_system_rate${RESET}\n"bash
➜ 0902 git:(main) bash cpu_usage_calculator.sh
第 1 次 idle: 100.0
第 2 次 idle: 99.5
第 3 次 idle: 99.5
使用 awk 计算的 CPU 使用率平均值 (cpu_idle_avg): 66.3333
使用 bc 计算系统使用率 (cpu_system_rate): 33.66
使用 awk 计算系统使用率 (cpu_system_rate): 33.67
cpu_usage_calculator.sh: line 29: let: 66.3333: syntax error: invalid arithmetic operator (error token is ".3333")
计算的 CPU 使用率平均值 (cpu_idle_avg_int): 66
使用 let 计算系统使用率 (cpu_system_rate): 34
expr: non-integer argument
使用 expr 计算系统使用率 (cpu_system_rate): 34
cpu_usage_calculator.sh: line 42: 66.3333: syntax error: invalid arithmetic operator (error token is ".3333")
使用 $(()) 计算系统使用率 (cpu_system_rate): 34