29

I'd like to print at the very least print # files extracted, from running a tarball extract

xz -dc /path/to/somearchive.tar.xz | sudo tar xvpf - -C /path/to/some_directory

I was thinking of using the "\r" as mentioned in this question, for instance

num=0
when [\n received]
    num=$(($num + 1))
    echo -ne "$num files extracted \r"
end when

my bash skills fail me.

Community
  • 1
  • 1
GlassGhost
  • 16,906
  • 5
  • 32
  • 45

5 Answers5

63

Using pv to pipe the file to tar.

  1. Firstly, you'll need to install pv, which on macOS can be done with:

    brew install pv
    

    On Debian or Ubuntu, it can be done with: apt install pv (Thanks @hyperbola!).

  2. Pipe the compressed file with pv to the tar command:

    pv mysql.tar.gz | tar -xz   
    

Here's the sample output of this command:

Sample output

For those curious, this works by pv knowing the total file size of the file you pass it and how much of it has been "piped" to the tar command. It uses those two things to determine the current progress, the average speed, and the estimated completion time. Neat!

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
41

When extracting with tar you can use the --checkpoint option. What you get is not really a progress bar but good enough to see the progress.

In this example, tar will print a message each 100 records written. If you place a dot immediately after the equal sign, it will just print a ..

tar -xf somearchive.tar.gz --checkpoint=.100

Output:

.......
sergej
  • 17,147
  • 6
  • 52
  • 89
  • This should be the accepted answer, simple yet useful +1. – gorjan Jun 17 '21 at 00:02
  • This just shows `...` without its 100% percent – alper Nov 17 '21 at 10:47
  • 3
    This doesn't seem to work on centos release 8 with gnu tar v1.30. What works on gnu tar is: `tar xvnf archive.tgz --checkpoint=1000 --checkpoint-action=dot`. This was introduced in [v1.20](http://git.savannah.gnu.org/cgit/tar.git/tree/NEWS#n781) – akhan May 23 '22 at 17:49
  • Per @royarisse's answer, we can make tar to print 1 dot for roughly 1% by adjusting the checkpoint size, e.g. in bash `tar -xf somearchive.tar.gz --checkpoint=$(($(stat -c %s somearchive.tar.gz)/512/20/100)) --checkpoint-action=.` – Lacek Mar 23 '23 at 15:21
14

If you really want to do it by file you could use:

tar xvpf /path/to/archive.tar.xz -C /path/to/dir 2>&1 | 
while read line; do
    x=$((x+1))
    echo -en "$x extracted\r"
done

Notes:

  • You probably don't need to xz separately, most tar implementations will automatically detect and decompress it for you.
  • tar reads from stdin by default, you don't need f -.

You should look into using pv instead, it's more precise and more generally applicable:

pv /path/to/archive.tar.xz | tar xp -C /path/to/dir
Flint
  • 1,651
  • 1
  • 19
  • 29
Kevin
  • 53,822
  • 15
  • 101
  • 132
  • You forgot `xzcat` in your `pv` sample: `pv /path/to/archive.tar.xz | xzcat | sudo tar -xpC /path/to/dir` – F. Hauri - Give Up GitHub Oct 15 '13 at 02:57
  • Nice answer, didn't know that `tar` output could be sequentially piped like that – higuaro Oct 15 '13 at 02:59
  • @F.Hauri no I'm not, see my note about `tar` automatically detecting compression. – Kevin Oct 15 '13 at 03:00
  • @h3nr1x Yep, it's basically designed like any other command line utility, for pipelines. It just happens to normally take and output binary data. – Kevin Oct 15 '13 at 03:02
  • 1
    With `pv`, then, per file: `lines=$(tar -tJf archive.txz | wc -l); tar -xvpf archive.txz 2>&1 | pv -ls$lines` – kojiro Oct 15 '13 at 03:11
  • 1
    this: ```pv /path/to/archive.tar.xz | sudo tar xp -C /path/to/dir``` how could I make it an alias, so I could write something like: ```progtar inputfile destination/dir``` – Antero Duarte Jan 01 '16 at 18:07
  • Just *do* it. Don't **sudo** it all the time – Flint Jun 15 '18 at 21:38
  • I also apply whiptail: local x=0 tar -xvf "$archive" -C "$TEMPORARY_DIRECTORY" | while read line; do x=$((x+1)) echo $x done | whiptail --title "Установка" --gauge "Распаковка архива" 6 60 $x – Ilya Jun 16 '22 at 23:47
5

While the pv solution shows progress nicely, it doesn't show what files are extracted whereto. The --checkpoint=.100 option shows the files and indicates that it's working, but doesn't show progress.

On the Tar Checkpoints page I found some information about the --checkpoint-action option, which is able to execute some bash magic for every checkpoint. Knowing that a checkpoint is created every 20 blocks of 512 bytes (at least that's the default, see man tar), It's possible to get the progress based on the current block and the original size.

The snippet below can be saved as a bash file (or put into a bash function):

archive="$1"

originalsize=$(file $archive | rev | cut -d' ' -f1 | rev)
step=100
blocks=$(echo "$originalsize / 512 / 20 / $step" | bc)

tar -xvz --checkpoint=$step --totals \
 --checkpoint-action="exec='p=\$(echo "\$TAR_CHECKPOINT/$blocks" | bc -l);printf \"%.4f%%\r\" \$p'" \
 -f $archive

Then using it is very straightforward:

bash tarprogress.sh your.archive.tgz
royarisse
  • 331
  • 2
  • 9
2

You can do this with xz files like this:

unxz -v --stdout file.tar.xz | tar -x
tchap
  • 3,412
  • 3
  • 29
  • 46
Zen42
  • 43
  • 3