Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save cvladan/898c3ad14c5ba31806a131ae6bf39e28 to your computer and use it in GitHub Desktop.
Save cvladan/898c3ad14c5ba31806a131ae6bf39e28 to your computer and use it in GitHub Desktop.
A collection of scripts for listing packages installed later, after the initial setup in OpenWrt.

Get List of Packages I've Installed

Here are the OpenWrt shell scripts, which have only one purpose to help you get a real list of packages that you have installed using opkg after setting up OpenWrt. While it may seem like a simple task, it's not straightforward. I recommend checking out this README.md file in this Gist for instructions and recommendations on which script to use.

Displaying a list of packages that I have personally installed is not a straightforward problem, as the status "user installed" will include various other packages besides the ones I installed. Therefore, using the opkg status command will produce way too many results and only confuse you.

In a nutshell, the approach that works most effectively in scripts is to use package installation timestamps and compare them to some reference timestamp to determine exactly which packages I have installed. One reference that some scripts use, for instance, is the kernel installation timestamp, which is the one that couldn't have been installed later.


Here is the list of scripts mentioned in the original Gist from various sources, such as:

The basic and obvious script, for example by Kristaps Esterliņš, which would logically be expected to work correctly, but it does not. It is based on identifying "user installed" packages, which is not very accurate because there are many more such packages than those that I have installed. This is what I tried first and got disappointed.

If you don't have curl installed, it's usually easy to solve this by typing opkg install curl.

# download
wget -q https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-naive.sh -O ~/list-my-packages-naive.sh && chmod +x "$_"

# and run
~/list-my-packages-naive.sh

# or just run directly
curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-naive.sh | sh

The first viable solution was offered in a single Gist by Alfred Krohmer. However, in the comments, there are improved versions, all of which I tried, but in the end, I chose the one that displays the most accurate or minimal list of packages that I installed.

curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-inaccurate-and-slow.sh | sh

You'll notice that the script is slow and also rather inaccurate, so do not hesitate to interrupt it if you can't stand waiting.

There is a recommended improvement of this script. The script uses the busybox timestamp as a reference, but since you can update busybox via opkg update, its installation time is not ideal. The kernel is a part of the system that can't be installed via opkg, so it's better to use that instead, i.e. use opkg info kernel instead of opkg info busybox. In most cases both values will be the same, but in some cases using the kernel will be more accurate.

The updated version of the same script uses the same principle, but with a nicer appearance and significantly improved speed. It also generates files that contain lists of packages. However, the script is still just as inaccurate as before.

curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-inaccurate-fancy.sh | sh

The following script by Eric Anderson is notably the fastest as it reads data from the file /usr/lib/opkg/status, without having to repeatedly execute opkg commands. More importantly, this script provides the best and most realistic results. The modified version of this script is my favorite and I actively use it.

curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-proper-concept.sh | sh

For the last script, it is necessary to install the bash package since ash is the default shell for OpenWrt. However, I do not want to install bash solely for the purpose of running a single script. Therefore, unfortunately, I have not tested it. Use it as you wish.

curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages-using-bash.sh | bash

The Script I'm Using

Finally, back to the list-my-packages-proper-concept.sh script, which gave by far the best results. I improved that script a bit and copied it to /usr/bin and use it as the opkg-my command. If you want to do the same, just type the following

wget -q https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages.sh -O /usr/bin/opkg-my && chmod +x "$_"

And you can always run it directly, without installation:

curl -s https://gist.githubusercontent.com/cvladan/898c3ad14c5ba31806a131ae6bf39e28/raw/list-my-packages.sh | sh
#!/bin/sh
# source: https://gist.githubusercontent.com/alfredkrohmer/8d4c2a5ab62e690772f3d9de5ad2d978/raw/list-user-installed-packages.sh
FLASH_TIME=$(opkg info busybox | grep '^Installed-Time: ')
for i in $(opkg list-installed | cut -d' ' -f1)
do
if [ "$(opkg info $i | grep '^Installed-Time: ')" != "$FLASH_TIME" ]
then
echo $i
fi
done
#!/bin/sh
# source: https://gist.github.com/alfredkrohmer/8d4c2a5ab62e690772f3d9de5ad2d978?permalink_comment_id=2133357#gistcomment-2133357
FLASH_TIME=$(opkg status busybox | awk '/Installed-Time/ {print $2}')
LIST_INSTALLED=$(opkg list-installed | awk '{print $1}')
PACKAGES_2_INSTALL="/tmp/packagelist-personal.txt"
SYSTEM_INSTALLED="/tmp/packagelist-system.txt"
if [ -e "$PACKAGES_2_INSTALL" ]; then
rm -f "$PACKAGES_2_INSTALL"
touch "$PACKAGES_2_INSTALL"
else
touch "$PACKAGES_2_INSTALL"
fi
if [ -e "$SYSTEM_INSTALLED" ]; then
rm -f "$SYSTEM_INSTALLED"
touch "$SYSTEM_INSTALLED"
else
touch "$SYSTEM_INSTALLED"
fi
echo
echo "Getting a list of the current manually installed packages (this may take a minute or two):"
echo
for i in $LIST_INSTALLED; do
if [ "$(opkg status $i | awk '/Installed-Time:/ {print $2}')" != "$FLASH_TIME" ]; then
echo $i | tee -a "$PACKAGES_2_INSTALL"
else
echo $i >> "$SYSTEM_INSTALLED"
fi
done
echo
echo "The current list of MANUALLY installed packages is available at: \"$PACKAGES_2_INSTALL\""
echo
echo "A list of the packages installed by the SYSTEM at FLASH TIME is available in the file: \"$SYSTEM_INSTALLED\""
echo
exit 0
#!/bin/sh
# source: https://gist.githubusercontent.com/esters/a0d54b9edaf497be4ba7f8e7c92b1e3c/raw/openwrt-user-installed-packages.sh
#
for o in `opkg list-installed | awk '{ print $1}'`
do
opkg status $o | grep "user installed" -B 3 | awk '/Package:/{print $2}'
done
#!/bin/sh
# source: https://gist.githubusercontent.com/ejona86/26974041ebbb3bf6602bd1bee0f92860/raw/list-user-installed-packages.sh
FLASH_TIME="$(awk '
$1 == "Installed-Time:" && ($2 < OLDEST || OLDEST=="") {
OLDEST=$2
}
END {
print OLDEST
}
' /usr/lib/opkg/status)"
awk -v FT="$FLASH_TIME" '
$1 == "Package:" {
PKG=$2
USR=""
}
$1 == "Status:" && $3 ~ "user" {
USR=1
}
$1 == "Installed-Time:" && USR && $2 != FT {
print PKG
}
' /usr/lib/opkg/status | sort
#! /bin/bash
# source: https://gist.githubusercontent.com/don-coleman/2218210aec58986acc80467f9a15d42b/raw/opkguinstalled
#
# We use bash associative arrays indexed by the package name.
#
opkg status \* | {
declare -A packages
declare -A packages_depends
declare -A packages_skip
declare -A packages_time
while read -r line; do
case "$line" in
"Package: "* )
name="${line:9}"
packages["$name"]="$name"
;;
"Depends: "* )
[ ! -v name ] && continue
# strip the leading label
line="${line:9}"
# strip version specs
line="${line//(=*)/ }"
# strip trailing commas
line="${line//,\ /\ }"
#echo packages_depends["${name}"]="$line"
packages_depends["${name}"]="$line"
;;
"Installed-Time: "* )
[ ! -v name ] && continue
time="${line:16}"
if [ ! -v OLDEST_TIME ] || [ "$time" -lt "$OLDEST_TIME" ]; then
OLDEST_TIME="$time"
fi
packages_time["${name}"]="${line:16}"
;;
"Auto-Installed: yes" )
[ ! -v name ] && continue
packages_skip["${name}"]=1
;;
"" ) # Empty line delinenates individual package blocks
unset name
;;
esac
done
# pass over all the packages with dependancies, and mark the packages they
# depend on to be skipped (since they are an implied install).
for name in "${!packages_depends[@]}"
do
# as package names can have shell special characters in them,
# roll our own list processing, paying attention only to spaces.
depend_list="${packages_depends["$name"]}"
# take each item upto the next space (skipping all leading spaces)
while [[ $depend_list =~ ([^[:space:]]+)(.*) ]]; do
# mark this dependancy to be skipped.
packages_skip["${BASH_REMATCH[1]}"]=1
# update list
depend_list="${BASH_REMATCH[2]}";
done
done
#echo "${!packages[@]}"
# now print the name of all the "not skipped" packages which were not
# installed at the very beginning.
for name in "${!packages[@]}"
do
[ ! -v packages_skip["${name}"] ] && [ "${packages_time["${name}"]}" -gt "${OLDEST_TIME}" ] && echo "${name}"
done | sort
}
#!/bin/sh
# original: https://gist.githubusercontent.com/ejona86/26974041ebbb3bf6602bd1bee0f92860/raw/list-user-installed-packages.sh
# improved: https://gist.github.com/alfredkrohmer/8d4c2a5ab62e690772f3d9de5ad2d978?permalink_comment_id=3637214#gistcomment-3637214
PACKAGELIST_PERSONAL="/tmp/packagelist-personal.txt"
echo
echo "The list of manually installed packages:"
echo
DISTRI_TIME=$(grep Installed-Time /usr/lib/opkg/status | sort | head -n1)
while read -r line; do
case "$line" in
"Package: "*)
package="$line"
_skip=false;;
"${DISTRI_TIME}")
_skip=true;;
"Auto-Installed: yes")
_skip=true;;
"") # Empty line delimenates individual package blocks
[ "$_skip" = true ] || echo "$package" | awk '{print $2}';;
esac
done < /usr/lib/opkg/status | sort | tee "$PACKAGELIST_PERSONAL" | xargs -n1 printf " > %s\n"
echo
echo "The same list of manually installed packages can be found at: \"$PACKAGELIST_PERSONAL\""
echo
# placeholder file used only for naming the gist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment