netbsdnoob Checking which packages (not yet installed) contain a certain file/program?
You can search for packages using a regex pattern right now:
pkgin search ^firefox
but, to search for binaries inside all packages in the repository, you need to keep a package -> binary
mapping.
Ubuntu has a command-not-found
for this, but, this isn't part of the apt
system. It's a separate package with its own database.
You can do a similar thing on NetBSD using this:
cnf.sh
#!/bin/sh
set -eu
command set -o pipefail 2>/dev/null || true
me=${0##*/}
URL=https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/9.3/All
DB=/tmp/cnf.txt # "database" path (change this!)
# For testing, scan only package beginning with `zo'.
# Change to `.+\.tgz' to scan all packages.
#
PAT='zo.+\.tgz'
mkdb=false
verbose=false
while getopts bv opt
do case $opt in
b) mkdb=true
;;
v) verbose=true
;;
esac
done
shift $((OPTIND - 1))
if $mkdb # build the database (once per quarterly release)
then P=$(ftp -Vo - "$URL/pkg_summary.gz" | gzip -dc |
grep -Ee "^FILE_NAME=$PAT" | cut -d= -f2-)
[ -n "$P" ] || { echo >&2 "$me: pkg_summary.gz failed"; exit 1; }
for pkg in $P
do $verbose && echo >&2 "$pkg"
ftp -Vo - "$URL/$pkg" | tar -xf - -O '+CONTENTS' | awk \
'
$1 == "@name" {
pkgname = $2
}
$1 ~ "^(s?bin/[^/]+|[^/]+/s?bin/[^/]+)$" { # only rec.: bin/*, sbin/*,
bins[N++] = $1 # FOO/bin/*, FOO/sbin/*
}
END {
for (i = 0; i < N; i++)
printf "%s:%s\n", pkgname, bins[i]
}
'
done > "$DB"
else # search the database
awk -F: -vME="$me" -vDB="$DB" \
'
function die(msg) {
printf "%s: %s\n", ME, msg > "/dev/stderr"
exit 1
}
function lastidx(s, ch, n) {
# return match(s, sprintf("%c[^%c]+$", ch, ch))
for (n = length(s); n > 0; n--)
if (substr(s, n, 1) == ch)
break
return n
}
BEGIN {
if (ARGC == 1)
die(sprintf("Usage: %s CMD...", ME))
for (i = 1; i < ARGC; i++)
CN[ARGV[i]] = "" # remove dups.; mark no pkgs.
while ((getline < DB) > 0) {
lineno++
if (NF != 2) # should not happen
die(DB ":" lineno ": bad line: " $0)
if ((n = lastidx($1, "-")) < 2) # "
die(DB ":" lineno ":" $1 ": bad pkgname")
pn = substr($1, 1, n - 1)
if ((n = lastidx($2, "/")) < 2) # "
die(DB ":" lineno ":" $2 ": bad filename")
cn = substr($2, n + 1)
if (cn in CN) # cmd. found
CN[cn] = CN[cn] " " pn # rec. pkgs. with cmd.
}
for (i = 1; i < ARGC; i++) {
if (A[ARGV[i]]++)
continue # skip dup.
if ((cn = CN[ARGV[i]]) == "") {
printf "%s: no pkg(s) found\n", ARGV[i] > "/dev/stderr"
bad++
} else
printf "%s:\t%s\n", ARGV[i], cn
}
exit bad ? 1 : 0
}
' "$@"
fi
# foo-1.1:bin/foo
# foo-1.1:bin/fool
# foo2-1.0:foo2/sbin/foo
# bar-x-y-1.0:bin/bar
# bar2-x-y-2.0:bar/bin/bar
# bar2-x-y-2.0:bar/sbin/barrier
# bar3-5.1:bar/bin/barrier
Edit the file and change PAT
as described; then build the "database" (once every quarter) with:
$ cnf.sh -b
Search using:
$ cnf.sh zoo zoxide zmu zkCli.sh zzz
zoo: zoo
zoxide: zoxide
zmu: zoneminder
zkCli.sh: zookeeper
zzz: no pkg(s) found
$
Enhancements, and how to hook this into a shell's command_not_found_handle()
machanism you can do. (For bash(1)
, read the COMMAND EXECUTION
section.)