Portál AbcLinuxu, 19. července 2025 07:45
Jak zařídit, aby příkaz cp ukazoval "progress bar" (ukazatel postupu) podobně jako wget? Stačí trocha poměrně nechutného čarování s strace a skript je na světě.
Tiskni
Sdílej:
/* * cwp.c: catenate with progress * * Copyright (c) 2001 Chris Lightfoot. All rights reserved. * */ static char rcsid[] = "$Id: cwp.c,v 1.2 2001/01/19 00:26:17 chris Exp $"; #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <sys/stat.h> #include <sys/time.h> #define BLOCKSIZE 65536 #define TIMESTEP 10. /* number of seconds over which rate will be calculated */ int columns = 80; /* width of screen */ /* timeoffset: * Returns the number of seconds since some time. */ float timeoffset(const time_t t0) { struct timeval tv; gettimeofday(&tv, NULL); tv.tv_sec -= t0; return (float)tv.tv_sec + 1e-6 * (float)tv.tv_usec; } /* size: * Return a string describing the size of something. */ char *strsize(const int width, const int len) { static char str[64]; if (len > 10000000) sprintf(str, "% *.1f Mb", width - 3, (float)len / 1048576.); else if (len > 10000) sprintf(str, "% *.1f Kb", width - 3, (float)len / 1024.); else sprintf(str, "% *d b", width - 2, len); return str; } /* file_copy_progress: * Copy data from a file to some file descriptor, with a progress indicator * which indicates what fraction of the file has been copied. */ void file_copy_progress(char *f, int o, size_t size) { int i; ssize_t j, total = 0; char *buf; time_t tst; float t0 = 0., t1, t2; ssize_t n0, n1, n2; i = open(f, O_RDONLY); if (i == -1) { perror(f); return; } buf = (char*)malloc(BLOCKSIZE); tst = time(NULL); t0 = timeoffset(tst); n0 = 0; while ((j = read(i, buf, BLOCKSIZE))) { ssize_t k; float rate; if (j == -1 && errno != EINTR) { fprintf(stderr, "\n"); perror(f); close(i); free(buf); return; } for (k = 0; k < j; ) { ssize_t l; l = write(o, buf + k, j - k); if (l == -1 && errno != EINTR) { fprintf(stderr, "\n"); perror(f); close(i); free(buf); return; } k += l; total += l; } t1 = timeoffset(tst); if ((t1 - t0) > TIMESTEP / 2.) { t2 = timeoffset(tst); n2 = total; } if ((t1 - t0) > TIMESTEP) { t0 = t2; n0 = n2; } /* Print a progress indicator. */ fprintf(stderr, "%.*s: written %s/", columns - 55, f, strsize(9, total)); fprintf(stderr, "%s % 5.1f%% ", strsize(9, size), 100. * ((float)total/(float)size)); rate = ((float)(total - n0) / (t1 - t0)); if (rate < 0.) rate = 0.; if (rate > 1e7) fprintf(stderr, "% 5.1f Mb/s", rate / 1048576.0); else if (rate > 1e4) fprintf(stderr, "% 5.1f Kb/s", rate / 1024.0); else fprintf(stderr, "% 5.1f b/s", rate); fprintf(stderr, " \r"); } free(buf); } /* pipe_copy_progress: * Copy data from a nonseekable thing to a file descriptor, with a progress * indicator which indicates how many bytes have been copied. */ void pipe_copy_progress(char *f, int i, int o) { ssize_t j, total = 0; char *buf; time_t tst; float t0 = 0., t1, t2; ssize_t n0, n1, n2; buf = (char*)malloc(BLOCKSIZE); tst = time(NULL); t0 = timeoffset(tst); n0 = 0; while ((j = read(i, buf, BLOCKSIZE))) { ssize_t k; float rate; if (j == -1 && errno != EINTR) { fprintf(stderr, "\n"); perror(f); close(i); free(buf); return; } for (k = 0; k < j; ) { ssize_t l; l = write(o, buf + k, j - k); if (l == -1 && errno != EINTR) { fprintf(stderr, "\n"); perror(f); close(i); free(buf); return; } k += l; total += l; } t1 = timeoffset(tst); if ((t1 - t0) > TIMESTEP / 2.) { t2 = timeoffset(tst); n2 = total; } if ((t1 - t0) > TIMESTEP) { t0 = t2; n0 = n2; } /* Print a progress indicator. */ fprintf(stderr, "%.*s: written %s ", columns - 20, f, strsize(9, total)); rate = ((float)(total - n0) / (t1 - t0)); if (rate < 0.) rate = 0.; if (rate > 1e7) fprintf(stderr, "% 5.1f Mb/s", rate / 1048576.0); else if (rate > 1e4) fprintf(stderr, "% 5.1f Kb/s", rate / 1024.0); else fprintf(stderr, "% 5.1f b/s", rate); fprintf(stderr, " \r"); } free(buf); } int main(int argc, char **argv) { char *s = getenv("COLUMNS"); int i; if (s && (i = atoi(s)) && i > 0) columns = i; signal(SIGPIPE, SIG_IGN); /* We would rather get an EPIPE return. */ /* FIXME should we reopen stderr as /dev/tty if !isatty(2)? */ /* Copy stdin to stdout. */ if (argc == 1) pipe_copy_progress("standard input", 0, 1); else if (argc == 2 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) { fprintf(stderr, "cwp: catenate with progress\n" "%s\n" "\n" " cwp file ...\n" " catenate the given files on standard output, giving a\n" " progress indication for each file on standard error\n" "\n" " cwp\n" " copy standard input to standard output, giving a\n" " progress indication on standard error\n" "\n" "Copyright (c) 2001 Chris Lightfoot <chris@ex-parrot.com>. Redistribute freely.\n", rcsid); } else { char **a; for (a = argv + 1; *a; ++a) { struct stat st; stat(*a, &st); if (S_ISREG(st.st_mode)) { file_copy_progress(*a, 1, st.st_size); fprintf(stderr, "\n"); } else { int fd; fd = open(*a, O_RDONLY); if (fd == -1) perror(*a); else pipe_copy_progress(*a, fd, 1); } } } }
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.