2

Launching rpm -ql <somerpm> lists files and directories contained in an rpm package. I am interested in only listing the files strictly speaking, not the directories.

Is there any flag or command that doesn't rely on checking each of the rpm -ql <somerpm> output individually whether it is a directory (as in performing a [ -d $line ] test in the shell on each line)?

AdminBee
  • 22,803
carce-bo
  • 145

3 Answers3

5

It would appear that rpm has no builtin option to suppress directories in the file list output.

However, you can use the --queryformat option (without -l) to print file modes and file names for each file, and then pipe the output to e.g. grep to exclude those entries whose mode field starts with d:

rpm -q --qf '[%{FILEMODES:perms} %{FILENAMES}\n]' some_rpm | grep -v '^d'

This would still print the mode fields of those entries that are actual files. In order to suppress that, you can use a slightly more complex sed program instead:

rpm -q --qf '[%{FILEMODES:perms} %{FILENAMES}\n]' some_rpm | sed -nE '/^[^d]/s/.* //p'

This will suppress output by default, consider only those lines that do not start with d, and remove the first column.


Previous version of the answer

However, you can use the fact that the verbose output will print an ls -l style list of the files, and pipe the output to e.g. grep to exclude those entries whose permissions field starts with d:

rpm -ql -v some_rpm | grep -v '^d' 

Note that this will still retain the "full" output style. If you want to restrict the output to the actual filename, you could pipe the output to a slightly more complex awk program that will only print the last column, which is the actual filename. I have included a check to see if the file is a symlink, identified by -> as next-to-last column, in which case it will print the link name instead of the link target:

rpm -ql -v some_rpm | awk '$1 !~ /^d/ {if ($(NF-1) != "->") {print $NF;} else {print $(NF-2)}}'

This will, however, stumble upon filenames with whitespace in it, so you need to be careful here.

AdminBee
  • 22,803
3

There are a couple of options to restrict the output:

-c, --configfiles
  List only configuration files (implies -l).

-d, --docfiles List only documentation files (implies -l).

But nothing for all files (and only files) from what I can see. So, similar to AdminBee's answer, I'd suggest processing the output, but instead using the --dump option:

--dump  Dump file information as follows:

path size mtime md5sum mode owner group isconfig isdoc rdev symlink

This option must be used with at least one of -l, -c, -d.

Inspecting the output of an example package (like bash), the md5sums of both directories and symlinks are all zeros, but if the entry isn't for a symlink, the last column is X. So:

  • To print only directories:

    rpm -q -l --dump package | awk '$4 ~ /^0+$/ && $NF == "X" {print $1}'
    
  • To print only symlinks:

    rpm -q -l --dump package | awk '$4 ~ /^0+$/ && $NF != "X" {print $1}'
    
  • To print only files:

    rpm -q -l --dump package | awk '$4 !~ /^0+$/ && $NF == "X" {print $1}'
    

Example output from an Amazon Linux 2023 Docker Image:

$ rpm -q bash -l --dump | awk '$4 !~ /^0+$/ && $NF == "X" {print $1}' | head # Limiting output for regular files
/etc/skel/.bash_logout
/etc/skel/.bash_profile
/etc/skel/.bashrc
/usr/bin/alias
/usr/bin/bash
/usr/bin/bashbug-64
/usr/bin/bg
/usr/bin/cd
/usr/bin/command
/usr/bin/fc

$ rpm -q bash -l --dump | awk '$4 ~ /^0+$/ && $NF != "X" {print $1}' # Symlinks /usr/bin/bashbug /usr/bin/sh /usr/lib/.build-id/f2/caf7678bcb7e7d116f91109985f2f0209e714b /usr/share/man/man1/bashbug-64.1.gz /usr/share/man/man1/sh.1.gz

$ rpm -q bash -l --dump | awk '$4 ~ /^0+$/ && $NF == "X" {print $1}' # directories /usr/lib/.build-id /usr/lib/.build-id/f2 /usr/share/doc/bash /usr/share/licenses/bash


Looking at it a bit more, the mode also works: it seems that the mode starts with 04 (e.g., 040755) for directories and 012 (e.g., 0120777) for symlinks, and 010 for regular files, so that could be used instead. So, for example, to print directories:

rpm -q -l --dump package | awk '$(NF - 6) ~ /^04/ {print $1}'

Or to list files:

rpm -q -l --dump package | awk '$(NF - 6) ~ /^010/ {print $1}'
muru
  • 72,889
2

libarchive as used by bsdtar, bsdcpio and many graphical archive extractors supports RPM files, so you could for instance use bsdtar to convert the RPM to tar format on the fly and use star to filter archive members by type using its -find option:

bsdtar cf - @file.rpm | star tf - -find ! -type d

To exclude files of type directory or -type f instead of ! -type f to only include regular files, excluding all other types of files including directories, symlinks, devices, fifos...

Or, since GNU tar appends a / to the end of directories in its listing, if you can guarantee the RPM doesn't have members with newline in their paths:

bsdtar cf - @file.rpm | tar tf - | grep -v '/$'