shell与c语言完美结合,解析 df -h 命令中的 /dev/sd* 外设设备使用情况
1. 查看 /dev/sd* 设备的使用情况
在Linux系统下使用 df -h 获取系统挂载的设备信息,然后找到设备关键名称为 “/dev/sd” 开头的行,如:
df -h # -h 表示使用带单位的显示方式
结果如下:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
17G 7.4G 8.6G 47% /
/dev/sda1 99M 12M 82M 13% /boot
tmpfs 1014M 0 1014M 0% /dev/shm
/dev/sdb1 2.0G 36M 1.9G 2% /home/newdisk
.host:/ 30G 15G 16G 49% /mnt/hgfs
2. shell命令获取设备名称,大小,已用空间和可用空间的信息
使用shell命令的管道,grep和awk命令,解析 /dev/sd* 设备的信息,如:
df -h | grep -rns "/dev/sd[a-z]*" # 表示搜索关键字开头 sda 到 sdz 开头的设备
执行上面的结果输出如下:
4:/dev/sda1 99M 12M 82M 13% /boot
6:/dev/sdb1 2.0G 36M 1.9G 2% /home/newdisk
可以看到,设备名称 /dev/sda1 前面有一个 4/6和冒后(:)内容,这个是我们不需要的,原因在于我们使用grep是带了 -n 参数,表示行号。因此,修改如下即可:
df -h | grep -rs "/dev/sd[a-z]*"
结果如下:
/dev/sda1 99M 12M 82M 13% /boot
/dev/sdb1 2.0G 36M 1.9G 2% /home/newdisk
以上的结果便是我们解析出来的设备信息。
但以上的信息,我们只是需要设备名称,大小,已用空间和可用空间的信息,其他信息可以省略,因此使用awk命令输出 前4列 信息即可。即
df -h | grep -rs "/dev/sd[a-z]*" | awk '{print $1,$2,$3,$4}'
结果如下:
/dev/sda1 99M 12M 82M
/dev/sdb1 2.0G 36M 1.9G
3. 使用c语言结合获取设备信息
在第二步中我们已经获取到相应的设备信息,现在我们需要在 c语言上进行读取,实际上我们把第二步的 shell 命令 重定向 到一个文本上,然后利用读取文本的方式,解析出我们需要的数据。shell命令如下:
df -h | grep -rs "/dev/sd[a-z]*" | awk '{print $1,$2,$3,$4}' > 1.txt
3.1 c 语言执行 shell 命令,常规使用的有 system/popen/excel
在测试中,上述三个函数,无论使用任意一个,都是可以的,但在实际应用中,仍然需要根据实际进行选择,读者自行查询资料。 本次我们使用 popen 函数进行测试。
3.2 c语言重定向的 shell 字符串命令
// shell 字符串命令
#define redirect_name "1.txt"
#define get_disk_cmd "df -h | grep -rs \"/dev/sd[a-z]*\" | awk '{print $1,$2,$3,$4}' > " redirect_name
3.3 使用 popen 函数
3.3.1 popen 函数原型:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
也就是说,使用 popen 执行的shell命令,返回的是一个 FILE* 的文件操作指针,也需要使用 pclose 关闭,而不是使用 fclose 关闭。
command: 传入的为 shell 命令
type: 命令的操作类型,读出("r") / 写入("w")
返回: FILE 类型的文件指针。
具体使用如下:
FILE *fp = NULL;
fp = popen(get_disk_cmd, "r");
if(fp == NULL)
{
return -1;
}
pclose(fp);
fp = NULL;
3.4 使用 fopen/fgets/fclose/ssanf 函数读取重定向文件,获取数据
FILE *fp = NULL;
fp = fopen(redirect_name, "r");
if(fp == NULL)
{
return -1;
}
while(fgets(disk_info, 256, fp))
{
memset(disk_name, '\0', sizeof(disk_name));
memset(disk_size, '\0', sizeof(disk_size));
memset(disk_used_size, '\0', sizeof(disk_used_size));
memset(disk_avail_size, '\0', sizeof(disk_avail_size));
sscanf(disk_info, "%[^ ] %[^ ] %[^ ] %[^\n]", \
disk_name, disk_size, \
disk_used_size,disk_avail_size);
printf("name: %s\t\tsize: %s\tnused: %s\tavail: %s\r\n", \
disk_name, disk_size, \
disk_used_size, disk_avail_size);
}
fclose(fp);
fp = NULL;
我们使用 sscanf 函数的正则表达式来进行获取数据,也可以直接使用 %s 格式来获取,但有可能读取越界。
sscanf(disk_info, "%s %s %s %s\n", \
disk_name, disk_size, \
disk_used_size,disk_avail_size);
3.5 完整代码
#include <stdio.h>
#include <string.h>
#define redirect_name "1.txt"
#define get_disk_cmd "df -h | grep -rs \"/dev/sd[a-z]*\" | awk '{print $1,$2,$3,$4}' > " redirect_name
int main(int argc, char const *argv[])
{
FILE *fp = NULL;
char disk_info[256] = {'\0'};
char disk_name[128] = {'\0'};
char disk_size[32] = {'\0'};
char disk_used_size[32] = {'\0'};
char disk_avail_size[32] = {'\0'};
fp = popen(get_disk_cmd, "r");
if(fp == NULL)
{
return -1;
}
pclose(fp);
fp = NULL;
fp = fopen(redirect_name, "r");
if(fp == NULL)
{
return -1;
}
while(fgets(disk_info, 256, fp))
{
memset(disk_name, '\0', sizeof(disk_name));
memset(disk_size, '\0', sizeof(disk_size));
memset(disk_used_size, '\0', sizeof(disk_used_size));
memset(disk_avail_size, '\0', sizeof(disk_avail_size));
sscanf(disk_info, "%[^ ] %[^ ] %[^ ] %[^\n]", \
disk_name, disk_size, \
disk_used_size,disk_avail_size);
printf("name: %s\t\tsize: %s\tnused: %s\tavail: %s\r\n", \
disk_name, disk_size, \
disk_used_size, disk_avail_size);
}
fclose(fp);
fp = NULL;
return 0;
}
输出结果如下,与我们在终端窗口使用shell命令一样:
name: /dev/sda1 size: 99M nused: 12M avail: 82M
name: /dev/sdb1 size: 2.0G nused: 36M avail: 1.9G