There's an existing script to identify portage world-file entries that are dependencies of other packages, which can be useful if you've forgotten to specify "--one-shot" while fixing emerge issues, and similar.
However, it is now broken, as it relies on output from "qdepends -Q" that has changed significantly since the script was written, and also it performs like a dog as it issues "emerge --pretend --depclean" for each world file entry the isn't identified by the "qdepends" test.
It turns out that "emerge --pretend --quiet --depclean" works if you feed it the entire world file contents in the command line, and this takes not much longer than each of the individual runs in the old script. You can parse the output to generate a couple of reports, one of packages that are not dependencies of anything else (and therefore you may wish to retain in your world file), and one of packages that are dependencies, and therefore are candidates for consideration as "pollution" that can be removed with "emerge --deselect y".
Here's a new script to do that:
Code: Select all
#!/bin/sh
### Report on Portage world-file packages
# Paul Gover, Feb 2026
# A couple of essential portage paths
world_file=/var/lib/portage/world
vdb=$(portageq vdb_path)
# Identify myself for use in tempfile names
ME="${0##*/}" # strip off any path
ME="${ME%%.*}" # strip off any extension
# Some ANSI colour sequences
BLUE=$(printf '\033[34;1m')
WHITE=$(printf '\033[37;1m')
RESET=$(printf '\033[0m')
# We do everything in the portage installed package database
cd "$vdb" || { printf 'cd %s failed.\n' "$vdb" >&2 ; exit 1 ; }
root_pkgs() {
# A list of world-set packages that are required by nothing else
# The output up to the first blank line is a series of category/package lines
# shellcheck disable=SC2046
emerge -pq --depclean $(cat "$world_file")
}
disqualify() {
# Remove any qualification text following colons from a stream of files
# (for example, www-client/firefox:rapid, or
# games-util/steam-launcher::steam),
# but discarding all contents from the first blank line onwards
local finished pkg rest
while read -r pkg rest
do
[ "$finished" ] && continue
[ "" = "$pkg" ] && finished="true" && continue
printf '%s\n' "${pkg%%:*}"
done
}
describe() {
# Print the package name and its description from the portage database
local pkg rest
while read -r pkg rest
do
printdesc "$pkg" "$pkg"*/DESCRIPTION # This may match several files
done
}
printdesc() {
# Get the first Descriptions file, if any
# First parameter is the package name, second is a series of paths in the vdb
local pkg path cpn cp desc
pkg="$1"
shift
for path
do
cpn="${path%/DESCRIPTION}"
cp="${cpn%%-[0-9]*}" # p is everything up to the first version number field
[ "$pkg" = "$cp" ] || break # The path expansion in describe() might include "A" and "A-B" names
[ -r "$path" ] && read -r desc<"$path" # The last matching path will be the most up to date
done
if [ "$desc" ]
then printf '%-35s %s%s%s\n' "$pkg" "$BLUE" "$desc" "$RESET"
else printf '%s\n' "$pkg"
fi
}
tempf() {
# Create a tempf, using /run ramdisk if possible
local id dir
id="$(id -u)"
if [ "$id" = "0" ]
then
dir="${XDG_RUNTIME_DIR:-/run}"
[ -d "$dir" ] || dir=""
mktemp -p "$dir" "tmp.$ME$1.XXXXXXXXXX"
else mktemp -p "${XDG_RUNTIME_DIR}" "tmp.$ME$1.XXXXXXXXXX"
fi
}
# A couple of tmp files to fill
roots=$(tempf '-roots')
clean_world=$(tempf '-world')
# Filter the world file and emerge -pv --depclean output
# and sort and remove duplicate entries (depclean can definitely produce some)
root_pkgs | disqualify | sort -u > "$roots"
disqualify < "$world_file" | sort -u > "$clean_world"
# Packages in both files are world entries that are not dependencies
cat << END
The following reports list package names from your portage @world set,
for you to review and possibly remove if they are unnecessary.
Note that the reports considers neither package slots nor
repository names. If necessary, clarify package names using
equery list -F '\$cpv:\$slot::\$repo' <packname>
(Note the quotes are essential in the above command.)
Note also that this program identifies neither packages in a circular dependency,
nor dependents of virtual packages.
${WHITE}WORLD-FILE ENTRIES THAT ARE NOT DEPENDENCIES OF OTHER PACKAGES${RESET}
These should be packages that you want to retain.
But sometimes you get things included because you forgot
emerge's "--one-shot" (or "-1") parameter when you made changes
in response to a problem merging a particular package
(such as needing a specific USE flag or keywording).
Then there may be packages you installed for a test,
haven't used since, but never got around to deleting them.
Now is your chance to "emerge --depclean" them.
In particular, you are unlikely to need libraries unless unless
you are developing code.
END
comm -12 "$clean_world" "$roots" | describe
# Packages only in the roots file are dependencies of other packages
cat << END2
${WHITE}WORLD-FILE ENTRIES THAT ARE DEPENDENCIES OF OTHER PACKAGES${RESET}
These may be unnecessary entries that should be removed with "emerge --deselect y",
but not always; sometimes you install a package, only later to install another that
depends on the first.
It's not a crime to leave them in your world file,
but if you don't think you actively and explicitly use them,
it should be safe to deselect them.
END2
comm -23 "$clean_world" "$roots" | describe
# Cleanup
rm "$roots" "$clean_world"

