CLIツールって複数のツールを|(パイプ)で繋げていい感じに処理しやすいように作られているから余計な情報を表示しないものが結構多いですよね。でも時間がかかる処理を走らせているときに「今どこまで終わったんだっけ?」「そもそも動いてるのかな?」と不安になることもしばしばあります。
そこで今回はなんでもかんでもプログレスバーを表示ができるpvコマンドを紹介します。
pvとは
pvは「Pipe Viewer」の略です。あるコマンドとパイプでpvコマンドを繋ぐことでプログレスバーが表示できるようになります。進捗状況の算出にはpvコマンドに渡されたデータ量とパイプを通過したデータ量が使われます。
pvコマンドはcatコマンドと似たような動きをします。pvコマンドの引数にファイルを指定すると、そのファイルの中身を標準出力します。ファイルが未指定、あるいは-(ハイフン)を指定すると標準入力を待ち受け、受け取ったデータを標準出力に流します。
インストール
#pvとはで紹介した公式ページの「Packages and ports」に書かれています。パッケージが用意されていないディストリビューションをお使いの方は自前でビルドしてください。ビルド方法も公式ドキュメントに記載されています。
使い方
pvコマンドの使い方は2通りあります。pvコマンドを起点に処理を開始する方法と、コマンドとコマンドの間にパイプで繋げる方法です。
$ pv input > output
pvコマンドを起点に処理を開始する方法を解説します。
pvコマンドは引数にファイルを指定するとファイル内容を標準出力します。つまり、標準入力からデータを受け取って処理するCLIツールにpvコマンドからデータを流してあげるとバーが表示されるということです。
とりあえず実験で使うため1GBのファイルを用意しておきます。
$ fallocate -l 1G test.txt
fallocateコマンドが使用できない環境ならddコマンドでもOKです。
$ dd if=/dev/zero of=test.txt bs=1G count=1
それではtest.txtをgzipで圧縮してみたいと思います。
$ pv test.txt | gzip -c > test.txt.gz

gzip圧縮でプログレスバーを表示できました。
ファイルコピーを試してみます。
$ pv test.txt > test2.txt

ファイルサイズ的に一瞬で終わってしまいますが、別のファイルシステムなどにコピーしているときには有用かもしれません。
リモートにファイル転送を試してみます。
scpで転送する場合、scpは進捗状況を表示します。これで十分といえば十分なのですが、せっかくなのでプログレスバーも表示してみます。
$ pv test.txt | ssh ubuntu@192.168.100.141 'cat > test.txt'

sshの引数にリモートで実行するコマンドを指定しています。catでstdinのデータをtest.txtにリダイレクトしています。
$ command1 | pv | command2
pvコマンドをパイプで繋げる方法を解説します。
pvコマンドをコマンドとコマンドの間に挟んであげると、その間に流れるデータ量から進捗が表示されます。
tarでファイルの圧縮時に進捗表示を試してみます。
まずは圧縮対象となるディレクトリを作成し、そのディレクトリに先ほど作成した1GBのファイルをコピーしておきます。
$ mkdir test $ cp test.txt test
tarで圧縮します。
$ tar czf - test | pv > test.tar.gz

プログレスバーは表示されますが左側に予想残り時間(ETA)が表示されません。これはpvコマンドがtestディレクトリの容量をしらないので残り時間を算出できないためです。そんな時は-s(--size)オプションでファイルサイズを教えてあげます。
$ tar czf - test | pv -s $(du test | cut -f1) > test.tar.gz

次はddの進捗を表示してみましょう。
$ dd if=/dev/zero bs=1G count=1 | pv | dd of=out.img

今回もpvは総データ量を知らないので-sオプションでデータ量を教えてあげます。
また、最後にddの出力とpvのプログレスバーが被って表示が乱れています。-c(--cursor)オプションを指定することで表示が整います。-cオプションはキャリッジリターン(CR)を使ってたところをエスケープシーケンスを使用するように変更します。これは複数行の出力がある場合に表示が整います。
$ dd if=/dev/zero bs=1G count=1 | pv -c -s 1G | dd of=out.img

curlでファイルをダウンロードしてみましょう。
curlは-#(--progress-bar)オプションを指定すると簡易的ではありますが、プログレスバーを表示できます。
$ curl --progress-bar -O http://192.168.100.141:8080/test.txt

あまりにも簡素なので、-#オプションなしの方が情報が見やすいかもしれません。
pvで少しリッチにします。
$ size=$(curl -fsSI http://192.168.100.141:8080/test.txt | grep -i '^content-length:' | tr -d ' \r' | cut -d: -f2) $ curl -fsS http://192.168.100.141:8080/test.txt | pv -s $size -N test.txt > test.txt

curl -Iでヘッダー情報を取得して、そこからContent-Lengthを取得しています。Content-Lengthはダウンロードしようとしているファイルのサイズになるので、これをpvコマンドの-sに渡しています。今回pvコマンドに-N(--name)オプションを指定しているので、プログレスバーの左側に-Nに指定した文字列が表示されています。
複数コマンドを連結している場合、それぞれの進捗を表示するにはpvコマンドを進捗表示したいコマンドの後ろにパイプで繋げます。
$ pv -c -N source linux-6.12.8.tar.xz | xzcat | pv -c -N xzcat | gzip | pv -c -N gzip > linux-6.12.8.tar.gz

この例ではxzで圧縮されたファイルをgzに変換しています。書くコマンドの後ろでpvコマンドを実行し、それぞれのコマンドの進捗を表示しています。
まとめ
pvコマンドは工夫次第であらゆるコマンドの進捗を表示できます。バーの表示まではいらない場合progressというツールが簡単に使えますので、こちらもその内記事にしたいと思います。
