The Ur Project

Documenting the craft of stacking things so they remain stacked. For a very long time.

pkg-search(1)

NAME

pkg-search - search the repository chain by name, capability or file

SYNOPSIS

pkg search [options] query

pkg find [options] query

DESCRIPTION

You know roughly what you want, but not what it's called. Or you know the library some binary is screaming about, and you want to know who ships it. Or there's a file on disk and you'd like to know which package put it there. That's all one command.

By default the query is matched against package names. Each flag adds another thing to match against, and the results are added together. So pkg search ssl --provides finds everything with "ssl" in its name and everything that provides a capability with "ssl" in it.

How does a name match?

As a substring, ignoring case, against both the package name and the subpackage name. pkg search compress finds anything with "compress" anywhere in it.

How does a capability match?

The same way, against the namespace:name form of each capability. That's soname:libc.so.6 for a shared library, pkgconfig:glib-2.0 for a pkg-config module. You don't have to type the whole thing, but the more you type, the less noise you get.

Where does it look?

At the repository chain: everything the configured repositories make current. Building that index means parsing every current manifest in the chain, and that takes seconds. It's effectively the whole cost of the command.

If your question is about this machine, ask it with --installed. Then the chain is never touched, and the answer comes straight out of the installed set. That's a lot cheaper.

--file is the odd one out. Without --installed it searches the chain and the installed set, and every hit says which one it came from. If the installed state can't be read (the normal case when you're not root), you get a warning and still get the repository half of the answer. Under --installed there's no second half to fall back on, so an unreadable state is an error instead of a quiet "(no matches)".

FILE MATCHING

The rules are the same whether you're searching the chain or, under --installed, this machine. Matching is case-sensitive, because a path is an exact identifier, not prose. The slash decides what gets compared:

  • A query with a / in it matches the whole path: /usr/bin/gzip.
  • A query without one matches the file name alone. gzip finds /usr/bin/gzip, but not /usr/bin/gzip.1 or /usr/share/doc/gzip/README.

Two glob characters work on whichever of those the slash picked:

*
Any run of characters, including /.
?
Exactly one character.

So '*.so.6' asks for a file name at any depth, and '/usr/lib64/*' asks for everything under a directory. Quote your globs, or the shell eats them first.

OPTIONS

--provides
Also match packages whose provides capabilities contain the query.
--requires
Also match packages whose requires capabilities contain the query.
--conflicts
Also match packages whose conflicts capabilities contain the query.
--file
Also match packages that ship a file the query names. See FILE MATCHING.
--installed
Answer from the installed set alone, and never build the chain index. Works with every other flag; with --file it answers which installed package ships a path.

All global options apply; see pkg(1).

OUTPUT

File hits come first, in their own table. They're never collapsed, since a path lives in exactly one subpackage. Installed hits are listed before the chain's:

source package version path installed gzip/bin 1.13-4 /usr/bin/gzip Common gzip/bin 1.13-4 /usr/bin/gzip

Name and capability hits follow, collapsed to one row per package with the runtime subpackage classes in brackets:

alsa-lib 1.2.16.1 [/bin, /lib] alsa-lib/dev 1.2.16.1

A capability hit tacks on what matched, past the bracket. What matched is part of what decides whether two subpackages may share a row, so two subpackages that matched for different reasons never fold together:

openssl 3.5.7 [/lib] (provides soname:libssl.so.3)

--collapse=none gives you one row per subpackage instead. The two levels that only make sense for an installed listing, sets and roots, are refused here; see pkg(1) and pkg-list(1).

And when there's nothing:

(no matches)

JSON

{ "ok": true, "query": "gzip", "hits": [ { "name":..., "subpkg":..., "version":..., "matched": [ { "rel": "provides", "capability": "..." } ] } ], "file_hits": [ { "source":..., "name":..., "subpkg":..., "version":..., "release":..., "path":... } ] }

source is installed, or the name of the repository that answers for the package.

EXAMPLES

By name

pkg search vim pkg search compress

Who provides a shared library?

pkg search --provides soname:libc.so.6 pkg search --provides soname:libssl.so.3

Who provides a pkg-config module?

pkg search --provides pkgconfig:glib-2.0

Who needs a shared library?

Worth asking before you remove something:

pkg search --requires soname:libfoo.so.1

What conflicts with a capability?

pkg search --conflicts file:/usr/bin/awk

Which package owns this path?

pkg search --file /usr/bin/gzip

Which package ships a file, wherever it lives?

pkg search --file gzip

Every shared library at version 6

pkg search --file '*.so.6'

Everything under a directory

pkg search --file '/usr/lib64/pkgconfig/' pkg search --file '/etc/'

A single-character wildcard

pkg search --file 'gz?p'

Several subjects at once

Name, provides and file, in one query:

pkg search ssl --provides --file

Scripting

pkg --json search --provides soname:libz.so.1 \ | jq -r '.hits[] | "(.name)/(.subpkg)"'

Is a path owned by anything at all?

pkg --json search --file /usr/bin/gzip | jq '.file_hits | length'

Only the installed half:

pkg --json search --file /usr/bin/gzip \ | jq '.file_hits[] | select(.source == "installed")'

Asking only about this machine

pkg search --installed vim pkg search --installed --file /usr/bin/gzip pkg search --installed --provides soname:libc.so.6

This beats the jq filter above. The chain index is never built at all, instead of built and then thrown away.

Searching a repository that isn't configured

pkg --repo /srv/mirror/Common --repos-dir /nonexistent search vim

Why is this search slow?

pkg -v search --file '*.so'

The -v lines show the index build, which is the expensive part on a large chain. If the answer is only about this machine, --installed skips that phase entirely.

EXIT STATUS

0 whether or not anything matched. Finding nothing isn't an error. 1 when the search couldn't be run: the chain couldn't be built, or, under --installed, the installed state couldn't be read.

SEE ALSO

pkg(1), pkg-list(1), pkg-info(1), pkg-query(1), pkg-install(1), pkg-chain(7), pkg-subpkgs(7)

docs/design/dependency-kinds.md