Portál AbcLinuxu, 19. července 2025 07:45


Progress bar pro příkaz cp

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ě.

4.3.2010 09:33 | Robert Krátký | Humor


Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

4.3.2010 09:39 Foo Bar | skóre: 14
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Chtěl jsem napsat cosi jako oh the horrors, oh the horrors, ale pak jsem si všiml kategorie Humor :)
alblaho avatar 4.3.2010 09:49 alblaho | skóre: 17 | blog: alblog
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Bohužel mi to nefunguje. Každá aktualizace progresu se vypíše na nový řádek.
4.3.2010 12:36 pc2005 | skóre: 38 | blog: GardenOfEdenConfiguration | liberec
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Mě to funguje (pouštěl jsem to jako bash skript s parametrama). Akorát při velkých souborech (10MB) se ten progress bar nezastaví.
Limoto avatar 4.3.2010 10:27 Limoto | skóre: 32 | blog: Limotův blog
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Je tu i pár dalších řešení
4.3.2010 10:32 xm | skóre: 36 | blog: Osvobozený blog | Praha
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Use rsync, Luke! ;-) Ale jako hack je to opravdu luxusní (jen kdyby strace nebylo tak zatraceně pomalé :-)).
Svoboda je tím nejdůležitějším, co máme. Nenechte se o ní připravit, podporujte Pirátskou stranu!
4.3.2010 10:38 David Watzke
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Hehe, já občas použiju tar|pv, ale v KDE lze taky použít grafický kde-cp, a tak...
4.3.2010 12:48 jas | skóre: 13 | blog: blag
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Osobne som skor cakal, ze si pustia read only ftp server na / a pouziju wget, ale aj toto je riesenie. :)
4.3.2010 13:49 ruza
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
par let zpatky fungoval nedokumentovany prepinac "cp -g". nebyl v man ani napovede pres -h ale delal co bylo treba
4.3.2010 14:33 xm | skóre: 36 | blog: Osvobozený blog | Praha
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Nebyl to náhodou nějaký distribuční patch na coreutils? IMHO v oficiálních coreutils to není a nikdy nebylo.
Svoboda je tím nejdůležitějším, co máme. Nenechte se o ní připravit, podporujte Pirátskou stranu!
4.3.2010 15:39 Jiří J. | skóre: 34 | blog: Poutník | Brno
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
To já znám zas cwp.c :-)
/*
 * 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);
            }
        }
    }
}
Limoto avatar 4.3.2010 16:10 Limoto | skóre: 32 | blog: Limotův blog
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
copy standard input to standard output, giving a progress indication on standard error
Přesně tohle dělá pv...
4.3.2010 18:28 xurfa
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Taktak, pv je výtečné pro různé skriptíky...
4.3.2010 21:28 d.c. | skóre: 30
Rozbalit Rozbalit vše Re: Progress bar pro příkaz cp
Odpovědět | Sbalit | Link | Blokovat | Admin
Jeden známý mi kdysi vysvětloval, že podstatná část vývoje programování ve woknech spočívá ve vylepšování teploměrů a odhadů, jak mají běhat. Jestli se tahle věda jednou dostane do Linuxu, jdu od válu. :o)

Založit nové vláknoNahoru


ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.