0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

unzipの進捗状況をプログレスバーで表示させる

Last updated at Posted at 2025-04-09

大量のファイルを包んだ zip ファイルを unzipコマンドで展開すると,大量のファイル名がズラズラと表示され,その出力処理のオーバーヘッドで,時間が無用にかかってしまいます。

$ unzip LargeArchive.zip -d DestDir
Archive:  LargeArchive.zip
   creating: ...
   (以下大量にファイル名表示の行が続く)➡ 時間が無用にかかる!

unzip-q オプション(quiet)を渡せば出力を消して黙らせることができますが,すると今度は展開処理中に反応がなく止まってしまい,あたかもフリーズしたように見えてしまいます。

理想は,進捗状況を表すプログレスバーが表示されることですが,残念ながら unzip の標準機能ではそのような機能は用意されていません。そこで,Pipe Viewerpvコマンド)を噛ませることで,プログレスバー表示の unzip を実現しましょう。

pv コマンドのインストール

pv コマンド(pipe viewer)を,何らかの方法でインストールします。

Homebrew

brew install pv

MacPorts

sudo port install pv

ソースから (configure & make)

公式サイトconfigure & makeによるソースコードからのビルド手順の解説があります。

Universal Binary としてビルドする手順は次の記事に記しました。

pv & unzip のラッパーとなるシェル関数を定義

pv_unzip というシェル関数を,次のように定義します。

function pv_unzip() {
  local unzip_opts=()
  local zipfile=""
  local outdir=""

  # 引数を解析
  while [[ $# -gt 0 ]]; do
    case "$1" in
      -*)
        unzip_opts+=("$1")
        shift
        ;;
      *)
        if [[ -z "$zipfile" ]]; then
          zipfile="$1"
        elif [[ -z "$outdir" ]]; then
          outdir="$1"
        else
          echo "Too many arguments" >&2
          return 1
        fi
        shift
        ;;
    esac
  done

  # 引数チェック
  if [[ -z "$zipfile" ]]; then
    echo "Usage: pv_unzip [unzip options] zipfile.zip [output_dir]" >&2
    return 1
  fi

  # outdir が未指定の場合はカレントディレクトリを使用
  if [[ -z "$outdir" ]]; then
    outdir="."
  fi

  # ファイルとディレクトリの存在チェック
  if [[ ! -f "$zipfile" ]]; then
    echo "Error: '$zipfile' does not exist or is not a file" >&2
    return 1
  fi
  if [[ ! -d "$outdir" ]]; then
    mkdir -p "$outdir" || { echo "Error: Cannot create '$outdir'" >&2; return 1; }
  fi

  # pv の存在確認と処理の分岐
  if command -v pv >/dev/null 2>&1; then
    # pv がある場合:進捗表示付きで展開
    local total_files
    total_files=$(unzip -l "$zipfile" | sed -n '/-----/,/-----/p' | sed '1d;$d' | wc -l)
    unzip "${unzip_opts[@]}" -d "$outdir" "$zipfile" | pv -l -s "$total_files" > /dev/null
    local unzip_status=${PIPESTATUS[0]}  # unzip の終了ステータスを取得
    return "$unzip_status"
  else
    # pv がない場合:通常の unzip で展開
    unzip "${unzip_opts[@]}" -d "$outdir" "$zipfile"
    return $?  # unzip の終了ステータスをそのまま返す
  fi
}

この中で,

total_files=$(unzip -l "$zipfile" | sed -n '/-----/,/-----/p' | sed '1d;$d' | wc -l)

の部分は,zipアーカイブ内の総ファイル数を取得しています。ヘッダ行などファイル名以外の部分を除外するために,----- で囲まれたファイルリスト部分を取り出し,最初の1行(-----)と最後の1行(-----)を削除(sed '1d;$d')して,その行数をカウント(wc -l)することで,zipアーカイブ内の総ファイル数を調べているわけです。

使い方

pv_unzip [unzip options] ARCHIVE.zip [output_dir]
  • -o (overwrite) のようなオプションを指定すると,それがそのまま unzip コマンドに伝えられます。
  • ただし,本来の unzip コマンドにある -d(出力先ディレクトリ)オプションは不要で,第2引数に出力先ディレクトリを指定します。
  • 第2引数(出力先ディレクトリ)の指定を省略した場合は,カレントディレクトリに展開されます。
  • pv コマンドがインストールされていない場合は,普通の unzip コマンドにフォールバックされます。

動作中の様子

image.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?