#!/bin/sh # pacsize -- display package sizes # # Copyright (C) 2014 Pierre Neidhardt # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . readonly myname='pacsize' readonly myver='4.1.2' calc_total () { awk 'BEGIN { unit["B"] = 1/1024 unit["KiB"] = 1 unit["MiB"] = 1024 unit["GiB"] = 1048576 unit["TiB"] = 1073741824 unit["PiB"] = 1099511627776 unit["EiB"] = 1125899906842624 unit["ZiB"] = 1152921504606846976 unit["YiB"] = 1180591620717411303424 } { u=$1 gsub(/[[:digit:]]*/, "", u) n=$1 gsub(/[[:alpha:]]*/, "", n) total += unit[u]*n print } END { printf ("%7s KIB TOTAL\n", total) }' } error () { echo >&2 "$@" } ## Print size and name. We round to the lowest integer, this makes output ## lighter. filter () { awk -F ": " \ '$0 ~ "^Name" { pkg = $2 } $0 ~ "^Installed Size" { split($2, a, " ") printf ("%4d%-3s %s\n", a[1], a[2], pkg) }' } remove_duplicates () { awk '! table[$0]++' } usage () { cat <&2 Usage: ${0##*/} [OPTIONS] PACKAGES ${0##*/} -a [OPTIONS] Display the size of PACKAGES. Duplicates are removed if any. The local database is queried first; if the package is not found, the sync database is then used for lookup. Options: -a: Process all installed packages. -h: Show this help. -n: Sort output by name. -s: Sort output by size. -t: Print total. -V: Show version information. Examples: $ ${0##*/} -ast Convenient way to keep track of big packages. $ ${0##*/} \$(pactree -ld1 linux) Print the size of linux and all its direct dependencies. $ ${0##*/} -st \$(pacman -Qdtq) Print a grand total of orphan packages, and sort by size. EOF } version () { echo "$myname $myver" echo 'Copyright (C) 2014 Pierre Neidhardt ' } opt_sort=false opt_all=false opt_total=false while getopts ":ahnstV" opt; do case $opt in a) opt_all=true ;; h) usage exit ;; n) opt_sort="sort -k3" ;; s) opt_sort="sort -h" ;; t) opt_total="calc_total" ;; V) version "$0" exit ;; \?) usage exit 1 ;; esac done shift $((OPTIND - 1)) ## All-packages mode. ## We use a dedicated algorithm which is much faster than per-package mode. ## Unfortunately there is no easy way to select packages with this method. if $opt_all; then DBPath="$(awk -F "=[ \t]*" '/^[ \t]*DBPath[ \t]*=/{gsub(/[ \t]*$/, "", $2); print $2}' /etc/pacman.conf 2>/dev/null)" [ -z "$DBPath" ] && DBPath="/var/lib/pacman" if [ ! -d "$DBPath/local/" ]; then error "Could not find local database in $DBPath/local/." exit 1 fi awk 'BEGIN { split("B KiB MiB GiB TiB PiB EiB ZiB YiB", unit) } $0 == "%NAME%" { getline pkg } $0 == "%SIZE%" { getline size i = 1 while (size > 2048) { size /= 1024 i++ } printf ("%4d%-3s %s\n", size, unit[i], pkg) }' "$DBPath"/local/*/desc | { $opt_sort || cat ;} | { $opt_total || cat ;} exit fi ## Per-package mode. if [ $# -eq 0 ]; then error "Missing argument." usage exit 1 fi ## Remove this check if integrated to pacman. if ! command -v pacman >/dev/null 2>&1; then error "'pacman' not found" exit 1 fi { ## If package is not found locally (-Q), we use the sync database (-S). We ## use LC_ALL=C to make sure pacman output is not localized. buffer=$(LC_ALL=C pacman -Qi "$@" 2>&1 1>&3 3>&- | cut -f2 -d "'") [ -n "$buffer" ] && LC_ALL=C pacman -Si "$buffer" } 3>&1 | filter | { $opt_sort || remove_duplicates ;} | { $opt_total || cat ;}