Linux shell编程
- 一、快速入门
- 二、常用功能
- 1. 常用符号
- 1.1 `>`, `>>`, `&`, `&&`
- 2. 比较图片差异
- 3. 截屏
- 3.1 起X情况下(X window起桌面)
- 3.2 没有起X或没有X系统环境下
- 4. 自动输入密码
- 5. 查找根目录下以".ko"结尾的文件
- 6. 修改文件命名
- 7. 修改文件内容
- 三、句子记录
- 1. 获取CPU15min内平均负载
- 四、项目小脚本
- 1. 工具集成导致运行路径变化
一、快速入门
- 书籍:《Linux Shell 核心编程指南》丁明一
第一章边看边跑,看完就可以直接根据需求借助GPT边做边学。 - 直接上手写脚本:问GPT,验证脚本可用性,并针对不足要求GPT改进脚本实现功能,看不懂的句子让GPT解释shell用法和功能。
二、常用功能
1. 常用符号
1.1 >
, >>
, &
, &&
>
(重定向输出)
用于将命令的标准输出重定向到一个文件。如果文件已存在,它将覆盖文件的内容。>>
(追加输出)
用于将命令的标准输出追加到文件的末尾。如果文件不存在,它会创建一个新文件- 文件描述符 0、1、2
0:准输入stdin
1:标准输出stdout、
2:标准错误输出stderr。
常用command > output.txt 2>&1
将标准输出和标准错误输出都重定向到同一文件。 &
(后台执行)
用于将命令放入后台执行。这样可以继续在命令行中执行其他命令,而不必等后台任务完成。&&
(条件执行)
用于在前一个命令成功(返回状态码为0)时才执行后一个命令。它用于串联多个命令,保证前一个命令成功时才继续执行后一个命令。
2. 比较图片差异
if compare -metric AE p1.png p2.png null: 2>&1 | grep -v "0$"; then
echo "两张图片不同"
else
echo "两张图片相同"
fi
compare -metric AE p1.png p2.png null: 2>&1
:这部分代码使用 ImageMagick 的compare
命令来比较两张图片p1.png
和p2.png
的差异。其中,-metric AE
表示使用绝对误差(Absolute Error)作为度量标准。null:
是一个特殊的输出文件名,用于将结果输出到空设备,而不产生实际输出。2>&1
将错误输出重定向到标准输出,这样可以捕获错误信息。| grep -v "0$"
:使用管道将compare
命令的输出传递给grep
命令进行过滤。-v
参数表示只输出不匹配模式的行,“0$” 是一个正则表达式,表示以 0 结尾的行。所以这个部分的作用是删除输出中值为 0 的行。then echo "两张图片不同"
:如果compare
命令的输出中存在非零的行(即两张图片不同),则输出 “两张图片不同”。else echo "图片相同"
:如果compare
命令的输出中不存在非零的行(即两张图片相同),则输出 “图片相同”。fi
:表示条件语句的结束。
至于为什么除了图片是否相同的提示外还会输出数字,这是因为 compare
命令使用 -metric AE
参数时,会计算出两张图片的差异值,并将其作为输出之一。如果两张图片完全相同,则差异值为 0。而这段代码通过 grep -v "0$"
过滤掉了差异值为 0 的行,所以只要输出中存在非零行,就会被判断为两张图片不同。
如果你不希望输出差异值,可以将代码修改为以下形式:
if compare -metric AE p1.png p2.png null: 2>&1 | grep -v "0$" > /dev/null; then
echo "两张图片不同"
else
echo "两张图片相同"
fi
这样,通过将 grep
命令的输出重定向到 /dev/null
,就不会显示差异值了。
3. 截屏
3.1 起X情况下(X window起桌面)
可使用import截屏
import -window root screenshot.png
-
import
:这是ImageMagick软件包中的一个命令,用于从屏幕或窗口中截图。 -
-window root
:这是import命令的一个选项,指定要截取的窗口。在这种情况下,"root"表示截取整个屏幕。 -
screen.png
:这是截图保存的文件名。你可以根据需要更改文件名或路径。
请注意,为了运行该命令,你需要系统中已经安装了ImageMagick软件包。如果你在自己的计算机上运行该命令,请确保已正确安装ImageMagick,并且在命令行环境中可用。
import 和 convert 命令隶属于 ImageMagick 软件包。你可以通过运行以下命令来安装 ImageMagick 软件包
Debian/Ubuntu:sudo apt-get install imagemagick
CentOS/RHEL:sudo yum install ImageMagick
Arch Linux:sudo pacman -S imagemagick
3.2 没有起X或没有X系统环境下
进行截屏操作可以通过 Framebuffer 来实现。使用 fbgrab
命令来对 Framebuffer 进行截屏.
sudo apt install fbcat
sudo fbgrab screenshot.png
- 这会将 Framebuffer 的内容保存为 “screenshot.png” 文件。
命令执行后如有输出
pnmtopng: 2 colors found
- 表示截屏结果中只包含了两种颜色。这可能是因为 Framebuffer 中的内容较为简单,只有很少的颜色变化,导致截图结果中只有两种颜色。
请注意,该方法可能需要在系统中安装额外的软件包,并且可能需要适当的权限才能执行。另外,截图的质量和效果可能会根据系统和硬件的不同而有所差异。
补充:
fbgrab
命令获取当前系统中的 Framebuffer 内容的具体过程和细节涉及一些底层操作。下面是大致的工作流程:
-
打开 Framebuffer 设备:
fbgrab
首先尝试打开 Framebuffer 设备文件(通常是/dev/fb0
)。这个设备文件代表了系统中的主要 Framebuffer 设备。 -
获取 Framebuffer 信息:
通过调用ioctl
系统调用,fbgrab
会获取到关于 Framebuffer 的详细信息,包括分辨率、像素格式、每个像素的位数等。这些信息将帮助fbgrab
确定如何解析 Framebuffer 数据。 -
分配内存缓冲区:
fbgrab
根据 Framebuffer 的分辨率和像素格式,计算出需要的内存缓冲区大小,并分配足够的内存来存储 Framebuffer 的内容。 -
读取 Framebuffer 数据:
通过调用read
系统调用,fbgrab
将 Framebuffer 的内容读取到之前分配的内存缓冲区中。 -
转换和编码:
一旦 Framebuffer 的内容被成功读取到内存缓冲区中,fbgrab
将根据指定的输出格式(比如 PNG)对数据进行适当的转换和编码,以生成最终的图片数据。 -
保存为图片文件:
最后,fbgrab
将生成的图片数据写入一个指定的文件中,这个文件就是你在命令中指定的输出文件(比如 “screenshot.png”)。
总的来说,fbgrab
命令通过打开 Framebuffer 设备文件、读取数据、转换和编码数据,并将结果保存为图片文件的方式,获取当前系统中的 Framebuffer 内容。
需要注意的是,由于 fbgrab
涉及底层的操作,可能需要适当的权限才能执行。而且,不同系统和硬件的 Framebuffer 实现可能会有所不同,具体的细节也可能会有差异。
4. 自动输入密码
使用 read
命令和重定向来实现这个功能。具体操作如下:
-
在同目录下创建一个名为
password.txt
的文件,将密码写入该文件,然后保存。 -
在脚本中使用以下代码进行读取密码并自动输入:
#!/bin/bash
# 读取密码文件
password=$(cat password.txt)
# 执行需要密码的命令,并将密码传递给命令
echo $password | sudo -S command
其中,cat password.txt
命令用于读取 password.txt
文件中的内容,并将其赋值给变量 password
。sudo -S command
命令则是执行需要密码的命令,并通过 -S
参数将密码从标准输入中传递给命令。
这样,当需要输入密码时,脚本会自动从 password.txt
文件中读取密码,并将其传递给命令。人无需长时间观察脚本运行状态,也无需手动输入密码。
注意:为了确保密码的安全性,建议在脚本运行完毕后删除 password.txt
文件,或者将文件权限设置为仅当前用户可读写。
5. 查找根目录下以".ko"结尾的文件
在 Linux 系统中,你可以使用 find
命令来查找根目录下以 .ko
结尾的文件。以下是相应的命令示例:
find / -type f -name "*.ko"
这个命令将从根目录 /
开始,在整个文件系统中递归地查找文件名以 .ko
结尾的文件,并将它们列出。
请注意,由于这是一个递归操作,可能需要一些时间来完成。此外,由于在根目录下搜索,可能会需要管理员权限(使用 sudo
)才能访问某些文件和目录。
6. 修改文件命名
你可以使用 find
命令找到当前目录下所有含有 “gc_” 或 “gc_hal_” 的文件,并使用 sed
命令来进行替换。下面是一个简单的 Shell 脚本示例,实现了这一功能:
#!/bin/bash
# 查找当前目录下所有含有"gc_"或"gc_hal_"文件名的文件,并循环处理
find . -type f -name 'gc_*' -o -name 'gc_hal_*' | while read filename; do
# 将文件名中的"gc_"和"gc_hal_"替换为"ab_"
newname=$(echo $filename | sed -e 's/gc_/ab_/' -e 's/gc_hal_/ab_/')
# 执行重命名操作
mv "$filename" "$newname"
echo "Renamed $filename to $newname"
done
将上述代码保存到一个文件(比如 rename_files.sh
),然后给予执行权限:
chmod +x rename_files.sh
接着在当前目录下执行该脚本即可:
./rename_files.sh
这个脚本会遍历当前目录以及子目录中的所有文件,将文件名中的 “gc_” 和 “gc_hal_” 替换为 “ab_”。请注意,在运行脚本之前,请务必做好必要的备份工作,以免意外情况造成文件损坏。
7. 修改文件内容
你可以使用 sed
命令来修改文件内容中的特定词汇。下面是一个简单的 Shell 脚本示例,实现了将当前目录下所有文件中的 “gc_hal_” 和 “gc_” 替换为 “ab_”:
#!/bin/bash
# 查找当前目录下的所有文件,并循环处理
find . -type f -exec sed -i 's/gc_hal_/lj_/g; s/gc_/ab_/g' {} \;
将上述代码保存到一个文件(比如 modify_files.sh
),然后给予执行权限:
chmod +x modify_files.sh
接着在当前目录下执行该脚本即可:
./modify_files.sh
这个脚本会遍历当前目录以及子目录中的所有文件,将文件内容中的 “gc_hal_” 和 “gc_” 替换为 “ab_”。使用 -i
参数可以直接修改文件内容,而不需要输出到标准输出或者创建新文件。请注意,在运行脚本之前,请务必做好必要的备份工作,以免意外情况造成文件内容丢失或损坏。
三、句子记录
1. 获取CPU15min内平均负载
uptime | tr -s " " | cut -d" " -f13
这句 Shell 语句的作用是获取系统的运行时间(uptime)并提取出第 13 列。
让我们逐步解析这个命令的各个部分:
-
uptime
:这是一个 Linux 内置命令,用于显示系统的运行时间和平均负载。它会输出一行文本,类似于 “06:30:53 up 10 days, 4:23, 2 users, load average: 0.25, 0.32, 0.45”。 -
|
:这是管道符号,用于将一个命令的输出传递给下一个命令作为输入。 -
tr -s " "
:这是一个使用tr
命令的操作,意思是将连续的多个空格字符替换为一个空格字符。-s
选项表示压缩连续的重复字符。 -
cut -d" " -f13
:这是使用cut
命令的操作,通过指定分隔符和字段来提取特定列的内容。-d" "
:指定分隔符为空格。这样,cut
命令将使用空格作为字段的分隔符。-f13
:指定要提取的字段为第 13 列。cut
命令将根据指定的分隔符将输入的每行按列分割,并提取第 13 列的内容。
综上所述,这句 Shell 脚本的作用是从 uptime
命令的输出中提取出系统的运行时间,并输出为第 13 列的内容。
这个命令展示了一些常见的 Shell 编程技巧和用法:
- 使用管道符号
|
将多个命令连接在一起,实现数据的流式处理。 - 使用
tr
命令进行文本字符替换或删除操作,这里是将连续的多个空格字符替换为一个空格字符。 - 使用
cut
命令提取指定的列或字段,通过指定分隔符和字段来进行分割和提取操作。
这些技巧可以帮助您在 Shell 脚本中处理和转换文本数据。
四、项目小脚本
1. 工具集成导致运行路径变化
背景:
有一个测试程序2DTestTool,运行的命令为./go.sh
生成可执行文件2DTestTool
,然后运行./2DTestTool test
,是可以正常运行的。现在需要将该工具集成,放在case目录下,case下除2DTestTool还有其它测试工具,如3DTestTool等,运行命令同一改为./case/2DMassTestTool test
。但是这样会引起2DTestTool传下去的运行路径不一样,导致程序中涉及相对路径的文件读取都出现问题,现在需要给出脚本将该问题解决,不采用改变工具中相对路径内容的方式。
解决:
在 case 目录下运行脚本时,设置环境变量或修改当前目录。
#!/bin/bash
# 获取当前脚本所在的目录
SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
# 进入 2DMassTestTool 所在目录
cd $SCRIPT_DIR/2DTestTool
# 确保运行测试工具时的路径正确
./2DTestTool prepare
脚本详细解释:
# 获取当前脚本所在的目录
SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
-
$(dirname "$0")
:- 这部分代码获取当前脚本的路径。
"$0"
表示脚本文件的路径和名称。当我们运行脚本时,$0
会包含脚本的路径(相对或绝对路径)。dirname "$0"
会从这个路径中提取目录部分,即去掉脚本名称,只保留脚本所在的目录路径。- 举个例子,如果脚本的路径是
/home/user/script/go.sh
,那么dirname "$0"
就会返回/home/user/script
。
-
cd $(dirname "$0")
:- 这部分命令进入到脚本所在的目录。
cd
命令用于改变当前工作目录。 $(dirname "$0")
让cd
命令进入到脚本所在的目录。
- 这部分命令进入到脚本所在的目录。
-
pwd
:pwd
(print working directory)命令会输出当前工作目录的绝对路径。- 在这个上下文中,它返回的是脚本所在目录的绝对路径,并将结果赋值给变量
SCRIPT_DIR
。
-
SCRIPT_DIR=$(cd $(dirname "$0") && pwd)
:- 将
pwd
命令的输出(脚本的绝对路径)赋值给变量SCRIPT_DIR
。 SCRIPT_DIR
现在包含脚本文件所在目录的绝对路径,例如/home/user/script
。
- 将
变量解释:
SCRIPT_DIR
:保存当前脚本所在目录的绝对路径。$0
:脚本文件的名称或路径(相对或绝对路径),在这里用于获取脚本所在的目录。$SCRIPT_DIR/2DTestTool
:指向2DTestTool
目录的绝对路径,确保脚本能够找到并进入该目录。
通过这种方式,脚本能够在任意位置执行,并确保始终能够找到并正确运行 2DTestTool
工具,无论它在何处运行。