#!/bin/sh
ls -Ral | grep -E "^(\-|d).*$" | grep -vE ".* (\.\.|\.)$" | wc -l
需求:Linux下使用GUI(qt)执行 tar 命令。需要显示其过程和执行结果
设计:最初思路是想通过类似pv这样的命令实时输出执行比例和使用popen()函数监视执行结果。尝试很久无果,主要是pv或类似pv的命令都不要用(或许我没找到)。无意间关注到了ubuntu 文件管理器(nautilus)压缩与解压缩的GUI显示过程,从中得到了灵感。设计如下:
打包设计:
1,递归要打包的文件和/或文件夹,获取文件和文件夹总数量:X1。
2,使用popen()函数执行 tar 打包文件和/或文件夹命令,打包命令加上v(输出打包信息)参数。
3,fgets循环读取popen() fork() 的子进程 标准输出(stdout) 并记录行数:X2。
4,使用 X2 除以 X1 得出 tar 命令运行进度百分比。
5,将进度与步骤3中得到的 tar 输出信息(文件名) 显示到GUI中。
6,待命令操作完成时使用 pclose()得到 tar 执行结果(最终是否成功)并显示。
注:如果 tar 执行遇到错误 plcose() 可以捕捉到,但是却无法得到 tar 输出的错误信息,因为错误信息是输出到 stderr 中的。所以如果想要得到stderr中的异常信息,必须重写 popen() 和 pclose()。后面我会贴出 popen() 和 pclose() 源代码。会用 fork(),dup2() 与 pipi() 的 可以自行修改。
解包设计:
与打包设计类似,不同点在于步骤1的获取文件/文件夹数量上
部分实现:
打包:
步骤1:递归获取文件和文件夹数量命令实现
命令:ls 文件夹 -Ra | grep -vE "^.*:$|^$|^\.\.$|^\.$" | wc -l
命令说明:使用 ls 命令加 R(递归子目录)a(显示所有文件)获取所有文件和目录。使用 grep 命令加v(不显示匹配行)E(正则支持或)过滤掉 ls 命令的多余输出 和 “.” 和 “..” 文件夹。使用 wc -l 得到 总行数
步骤2:打包命令实现
命令实现:tar -zcvf 文件名.tar.gz 文件夹
命令说明:特别注意 v(输出打包过程)参数。需要注意的是 步骤1单次 ls 得到的文件/文件夹数量总是比步骤2的单个打包对象的数量少1。原因是因为 tar 命令输出了当前打包路径或文件。而 ls 则不是。注意:如果同时打包 N 个文件/文件夹 则 步骤2的数量比步骤1的数量多 N 。强迫症可以自己找平
解包:
步骤1:获取解压包文件数量
命令实现:tar -tzf 文件名.tar.gz | wc -l
命令说明:tar 的 t 参数是只输出文件信息,并不解压。wc -l 统计输出行数(也就是文件个数)
步骤2:解包
命令实现:tar -zxvf 文件名.tar.gz
命令说明: 注意加 v 参数
解包说明:我的实验对象是 linux内核源码包(linux-3.14.17.tar.gz),一共有48890个文件。由于里面没有大文件。所以步骤1与步骤2的时间几乎差不多。换句话说如果解包仅执行步骤2,耗时会省去一半。但是我看到Ubuntu解压缩这个包时候也是如此。所以我不建议省去步骤1,或许解压缩多个大文件打包的压缩包会有意义。解包步骤1过程也可能时间较长,因此注意执行解包步骤1时候进度条应该做loading显示
ls -Ral | grep -E "^(\-|d).*$" | grep -vE ".* (\.\.|\.)$" | wc -l
需求:Linux下使用GUI(qt)执行 tar 命令。需要显示其过程和执行结果
设计:最初思路是想通过类似pv这样的命令实时输出执行比例和使用popen()函数监视执行结果。尝试很久无果,主要是pv或类似pv的命令都不要用(或许我没找到)。无意间关注到了ubuntu 文件管理器(nautilus)压缩与解压缩的GUI显示过程,从中得到了灵感。设计如下:
打包设计:
1,递归要打包的文件和/或文件夹,获取文件和文件夹总数量:X1。
2,使用popen()函数执行 tar 打包文件和/或文件夹命令,打包命令加上v(输出打包信息)参数。
3,fgets循环读取popen() fork() 的子进程 标准输出(stdout) 并记录行数:X2。
4,使用 X2 除以 X1 得出 tar 命令运行进度百分比。
5,将进度与步骤3中得到的 tar 输出信息(文件名) 显示到GUI中。
6,待命令操作完成时使用 pclose()得到 tar 执行结果(最终是否成功)并显示。
注:如果 tar 执行遇到错误 plcose() 可以捕捉到,但是却无法得到 tar 输出的错误信息,因为错误信息是输出到 stderr 中的。所以如果想要得到stderr中的异常信息,必须重写 popen() 和 pclose()。后面我会贴出 popen() 和 pclose() 源代码。会用 fork(),dup2() 与 pipi() 的 可以自行修改。
解包设计:
与打包设计类似,不同点在于步骤1的获取文件/文件夹数量上
部分实现:
打包:
步骤1:递归获取文件和文件夹数量命令实现
命令:ls 文件夹 -Ra | grep -vE "^.*:$|^$|^\.\.$|^\.$" | wc -l
命令说明:使用 ls 命令加 R(递归子目录)a(显示所有文件)获取所有文件和目录。使用 grep 命令加v(不显示匹配行)E(正则支持或)过滤掉 ls 命令的多余输出 和 “.” 和 “..” 文件夹。使用 wc -l 得到 总行数
步骤2:打包命令实现
命令实现:tar -zcvf 文件名.tar.gz 文件夹
命令说明:特别注意 v(输出打包过程)参数。需要注意的是 步骤1单次 ls 得到的文件/文件夹数量总是比步骤2的单个打包对象的数量少1。原因是因为 tar 命令输出了当前打包路径或文件。而 ls 则不是。注意:如果同时打包 N 个文件/文件夹 则 步骤2的数量比步骤1的数量多 N 。强迫症可以自己找平
解包:
步骤1:获取解压包文件数量
命令实现:tar -tzf 文件名.tar.gz | wc -l
命令说明:tar 的 t 参数是只输出文件信息,并不解压。wc -l 统计输出行数(也就是文件个数)
步骤2:解包
命令实现:tar -zxvf 文件名.tar.gz
命令说明: 注意加 v 参数
解包说明:我的实验对象是 linux内核源码包(linux-3.14.17.tar.gz),一共有48890个文件。由于里面没有大文件。所以步骤1与步骤2的时间几乎差不多。换句话说如果解包仅执行步骤2,耗时会省去一半。但是我看到Ubuntu解压缩这个包时候也是如此。所以我不建议省去步骤1,或许解压缩多个大文件打包的压缩包会有意义。解包步骤1过程也可能时间较长,因此注意执行解包步骤1时候进度条应该做loading显示
#include <errno.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
static int *pids;
FILE *
popen(program, type)
char *program;
register char *type;
{
register FILE *iop;
int pdes[2], fds, pid;
if (*type != 'r' && *type != 'w' || type[1])
return (NULL);
if (pids == NULL) {
if ((fds = getdtablesize()) <= 0)
return (NULL);
if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
return (NULL);
bzero((char *)pids, fds * sizeof(int));
}
if (pipe(pdes) < 0)
return (NULL);
switch (pid = vfork()) {
case -1: /* error */
(void) close(pdes[0]);
(void) close(pdes[1]);
return (NULL);
/* NOTREACHED */
case 0: /* child */
if (*type == 'r') {
if (pdes[1] != fileno(stdout)) {
(void) dup2(pdes[1], fileno(stdout));
(void) close(pdes[1]);
}
(void) close(pdes[0]);
} else {
if (pdes[0] != fileno(stdin)) {
(void) dup2(pdes[0], fileno(stdin));
(void) close(pdes[0]);
}
(void) close(pdes[1]);
}
execl("/bin/sh", "sh", "-c", program, NULL);
_exit(127);
/* NOTREACHED */
}
/* parent; assume fdopen can't fail... */
if (*type == 'r') {
iop = fdopen(pdes[0], type);
(void) close(pdes[1]);
} else {
iop = fdopen(pdes[1], type);
(void) close(pdes[0]);
}
pids[fileno(iop)] = pid;
return (iop);
}
int
pclose(iop)
FILE *iop;
{
register int fdes;
sigset_t omask, nmask;
union wait pstat;
register int pid;
/*
* pclose returns -1 if stream is not associated with a
* `popened' command, if already `pclosed', or waitpid
* returns an error.
*/
if (pids == NULL || pids[fdes = fileno(iop)] == 0)
return (-1);
(void) fclose(iop);
sigemptyset(&nmask);
sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGQUIT);
sigaddset(&nmask, SIGHUP);
(void) sigprocmask(SIG_BLOCK, &nmask, &omask);
do {
pid = waitpid(pids[fdes], (int *) &pstat, 0);
} while (pid == -1 && errno == EINTR);
(void) sigprocmask(SIG_SETMASK, &omask, NULL);
pids[fdes] = 0;
return (pid == -1 ? -1 : pstat.w_status);
}