0

On some linux systems the following command will output a single large string

rpm -qa --qf '%{NAME} '

For those who don't have this command it outputs values with the following pattern:

a b c d e f g

I would like to exclude/filter out some of the strings from this output. In my case I would like to exclude anything that has "google" or "font" or "kernel" anywhere in the word. How would I do this? I've tried

grep -v -e "google"

but no output is returned.

For those without access to the rpm command I've provided the following sample data:

libabsl_crc_cord_state2508_0_0 libdwarves1 liblldb18 libopencore-amrnb0-32bit kservice libjq1 xdg-user-dirs libssl59 libzypp-plugin-appdata kf6-kcontacts libwpg-0_3-3 libQt6ShaderTools6 libXmu-devel busybox-static p11-kit-32bit google-noto-sans-armenian-fonts libgdiplus-devel yast2-slp libgcc_s1-32bit typelib-1_0-GdkPixdata-2_0 libgtkdatabox1 python313-cmdln libvisual-0_4-0 libgcab-1_0-0 typelib-1_0-GLibUnix-2_0 libKF5GuiAddons5 plasma6-nm-pptp libwx_gtk2u_propgrid-suse16_0_0 fontconfig-devel libQt6QmlMeta6 google-noto-sans-canadianaboriginal-fonts prctl libKF5UnitConversion5 plasma6-pa libwx_gtk2u_ribbon-suse16_0_0 libfontconfig1-32bit libQt6LabsSynchronizer6 libxvidcore4 libgraphite2-3-32bit dvd+rw-tools libKF6NewStuffWidgets6 luit libkdecorations3private2 google-noto-serif-oriya-fonts gtk3-metatheme-adwaita gtk3-branding-openSUSE libyajl2 xfce4-session-branding-openSUSE dbus-1 google-carlito-fonts catatonit gdbserver thunar libxml2-tools libass9 libdc1394-26 libabsl_vlog_config_internal2508_0_0 libabsl_flags_config2508_0_0 libKF6IconWidgets6 libfontconfig1 libvulkan_intel libQt6QuickShapes6 libzvbi0 libcap-ng-devel libqt5-qtxmlpatterns-imports
3
  • 2
    Wouldn't it be easier to get the output line-by-line instead, filter that and then join into one line if that's what you need finally? Commented Dec 6 at 7:12
  • 1
    @muru, they probably don't need to join with spaces, they may be trying to built a command line à la Microsoft Windows, while xargs or command substitution would split the list into a list of arguments (as you'd want to do on Unix-like systems) whether the items are delimited with space or newline. Commented Dec 6 at 8:20
  • 1
    maybe with rpm -qa --qf '%{NAME}\n' | grep -Fv -e google -e font -e kernel | paste -s -? Commented Dec 6 at 23:14

2 Answers 2

6

To remove space-separated words that contain a string, you could do something like:

rpm -qa --qf '%{NAME} ' |
  perl -lane 'print join " ", grep {! /google/} @F'

Where:

  • -lan is the awk mode where the -expression is evaluated for each line of input(s) (-n), split into fields (@F array) à la -awk, with the -line delimiter removed on input and added back on output.
  • grep {code} @list returns the elements of @list for which the code returns true.
  • join " " joins the result with spaces.

Or you could do:

rpm -qa --qf '%{NAME}\n' |
  grep -v google |
  paste -sd ' ' -

That is print a newline delimited list instead of space delimited one so you can use grep to filter it and then join the resulting lines with spaces using paste's -self-paste mode with space as -delimiter.

But if the point is that you want to pass that list as arguments to a command, then you don't need to have a space-delimited list. Unlike in Microsoft OSes, commands are not passed a command line string, they are passed a list of separate arguments, and in any case you'd need to split that list whether it's space-separated or newline-delimited, and the typical operators that do that splitting do it on newline as well as space by default.

cmd -- $(rpm -qa --qf '%{NAME}\n' | grep -v google)

in POSIX-like shells¹, command substitution ($(...) or the archaic form `...`), when left unquoted in list contexts splits the output of the command (trimmed of all trailing newline characters) on characters of $IFS (space, tab, newline (and nul in zsh) by default), and then performs globbing on the result (not in zsh nor fish) so would do what you want as long as package names don't contain space, tabs, nor wildcards (*, ?, [...]).

(
  set -o noglob
  IFS=$'\n'
  cmd -- $(rpm -qa --qf '%{NAME}\n' | grep -v google)
)

Would be more correct in sh implementations as splitting only on newline and disabling the globbing.

In zsh, you can use the f parameter expansion flag to split on newline (aka linefeed) only, would you have packages with space or tab in their name.

cmd -- ${(f)"$(rpm -qa --qf '%{NAME}\n' | grep -v google)"}

(also note the quotes around $(...) to disable the IFS-splitting).

The (t)csh equivalent:

cmd -- "`rpm -qa --qf '%{NAME}\n' | grep -v google`"

(when quoted, `...` splits on newline only, and no globbing is performed)

The rc (and derivatives) equivalent:

cmd -- `{rpm -qa --qf '%{NAME}\n' | grep -v google}

(splits on characters of $ifs, space, tab, newline by default; no globbing)

cmd -- ``('
'){rpm -qa --qf '%{NAME}\n' | grep -v google}

To split on newline only.


Or you can use xargs which splits on blanks² or newline and understands some form of quoting (though not in the same way as in any modern shell):

rpm -qa --qf '%{NAME}\n' | grep -v google | xargs cmd --

Would work as long as package names don't contain blanks, ', " or \ characters.

Note that it also affects the stdin of cmd.

With GNU xargs and a shell with support for Korn-style process-substitution:

xargs -rd '\n' -a <(rpm -qa --qf '%{NAME}\n' | grep -v google) cmd --
  • with -r, it avoids running cmd if the resulting list is empty (unlikely here)
  • with -d '\n', it splits on newline only
  • xargs will run cmd several times if the list of arguments is larger than execve()'s limit.
  • the list is passed as a filename argument to -a, so stdin is not affected.

¹ or recent versions of fish where they've added support for the Korn/POSIX style of command substitution. The native form of command substitution (but that cannot be used inside quoted strings) there is (...) alone. How it's split has changed a lot along fish history, but nowadays (cmd) or $(cmd) gives you the lines of the output of cmd, even empty ones, regardless of the value of $IFS, but bearing in mind that some of fish builtin commands are handled magically there.

² the list of blank characters varies with the xargs implementation and possibly locale but includes at least space and tab.

0

I dont have rpm in my system I have apt which prints in a different format. But I tried to simulate your sample output with the echo command like this...

$ echo libabsl_crc_cord_state2508_0_0 libdwarves1 liblldb18 libopencore-amrnb0-32bit kservice libjq1 xdg-user-dirs libssl59 libzypp-plugin-appdata kf6-kcontacts libwpg-0_3-3 libQt6ShaderTools6 libXmu-devel busybox-static p11-kit-32bit google-noto-sans-armenian-fonts libgdiplus-devel yast2-slp libgcc_s1-32bit typelib-1_0-GdkPixdata-2_0 libgtkdatabox1 python313-cmdln libvisual-0_4-0 libgcab-1_0-0 typelib-1_0-GLibUnix-2_0 libKF5GuiAddons5 plasma6-nm-pptp libwx_gtk2u_propgrid-suse16_0_0 fontconfig-devel libQt6QmlMeta6 google-noto-sans-canadianaboriginal-fonts prctl libKF5UnitConversion5 plasma6-pa libwx_gtk2u_ribbon-suse16_0_0 libfontconfig1-32bit libQt6LabsSynchronizer6 libxvidcore4 libgraphite2-3-32bit dvd+rw-tools libKF6NewStuffWidgets6 luit libkdecorations3private2 google-noto-serif-oriya-fonts gtk3-metatheme-adwaita gtk3-branding-openSUSE libyajl2 xfce4-session-branding-openSUSE dbus-1 google-carlito-fonts catatonit gdbserver thunar libxml2-tools libass9 libdc1394-26 libabsl_vlog_config_internal2508_0_0 libabsl_flags_config2508_0_0 libKF6IconWidgets6 libfontconfig1 libvulkan_intel libQt6QuickShapes6 libzvbi0 libcap-ng-devel libqt5-qtxmlpatterns-imports

I was able to solve using the following steps...

  1. Simulate output with the above echo command. This will print everything in a long space separated list.
  2. Piped this list into perl using xargs -0.
  3. In perl, split the string on whitespace and print the string if it does NOT contain Google, Font, or Kernel.

I also sorted the values in alphabetical order and printed each value on a separate line to make it easier to verify the output. If you do not want the value sorted, remove the sort command. And if you do not want each value on a separate line, replace the \n with a blank space in the print command.

Here is the code...

<your command> | xargs -0 perl -e 'for(sort split(/ +/,$ARGV[0])){print "$_\n" if(!/google|font|kernel/i);}'

I piped the echo command into perl using xargs -0, and the output looks like this

$ echo libabsl_crc_cord_state2508_0_0 libdwarves1 liblldb18 libopencore-amrnb0-32bit kservice libjq1 xdg-user-dirs libssl59 libzypp-plugin-appdata kf6-kcontacts libwpg-0_3-3 libQt6ShaderTools6 libXmu-devel busybox-static p11-kit-32bit google-noto-sans-armenian-fonts libgdiplus-devel yast2-slp libgcc_s1-32bit typelib-1_0-GdkPixdata-2_0 libgtkdatabox1 python313-cmdln libvisual-0_4-0 libgcab-1_0-0 typelib-1_0-GLibUnix-2_0 libKF5GuiAddons5 plasma6-nm-pptp libwx_gtk2u_propgrid-suse16_0_0 fontconfig-devel libQt6QmlMeta6 google-noto-sans-canadianaboriginal-fonts prctl libKF5UnitConversion5 plasma6-pa libwx_gtk2u_ribbon-suse16_0_0 libfontconfig1-32bit libQt6LabsSynchronizer6 libxvidcore4 libgraphite2-3-32bit dvd+rw-tools libKF6NewStuffWidgets6 luit libkdecorations3private2 google-noto-serif-oriya-fonts gtk3-metatheme-adwaita gtk3-branding-openSUSE libyajl2 xfce4-session-branding-openSUSE dbus-1 google-carlito-fonts catatonit gdbserver thunar libxml2-tools libass9 libdc1394-26 libabsl_vlog_config_internal2508_0_0 libabsl_flags_config2508_0_0 libKF6IconWidgets6 libfontconfig1 libvulkan_intel libQt6QuickShapes6 libzvbi0 libcap-ng-devel libqt5-qtxmlpatterns-imports | xargs -0 perl -e 'for(sort split(/ +/,$ARGV[0])){print "$_\n" if(!/google|font|kernel/i);}'
busybox-static
catatonit
dbus-1
dvd+rw-tools
gdbserver
gtk3-branding-openSUSE
gtk3-metatheme-adwaita
kf6-kcontacts
kservice
libKF5GuiAddons5
libKF5UnitConversion5
libKF6IconWidgets6
libKF6NewStuffWidgets6
libQt6LabsSynchronizer6
libQt6QmlMeta6
libQt6QuickShapes6
libQt6ShaderTools6
libXmu-devel
libabsl_crc_cord_state2508_0_0
libabsl_flags_config2508_0_0
libabsl_vlog_config_internal2508_0_0
libass9
libcap-ng-devel
libdc1394-26
libdwarves1
libgcab-1_0-0
libgcc_s1-32bit
libgdiplus-devel
libgraphite2-3-32bit
libgtkdatabox1
libjq1
libkdecorations3private2
liblldb18
libopencore-amrnb0-32bit
libqt5-qtxmlpatterns-imports
libssl59
libvisual-0_4-0
libvulkan_intel
libwpg-0_3-3
libwx_gtk2u_propgrid-suse16_0_0
libwx_gtk2u_ribbon-suse16_0_0
libxml2-tools
libxvidcore4
libyajl2
libzvbi0
libzypp-plugin-appdata
luit
p11-kit-32bit
plasma6-nm-pptp
plasma6-pa
prctl
python313-cmdln
thunar
typelib-1_0-GLibUnix-2_0
typelib-1_0-GdkPixdata-2_0
xdg-user-dirs
xfce4-session-branding-openSUSE
yast2-slp

I could not test this on my system without rpm, but it should work like so...

rpm -qa --qf '%{NAME} ' | xargs -0 perl -e 'for(sort split(/ +/,$ARGV[0])){print "$_\n" if(!/google|font|kernel/i);}'

Let me know if that returns the output you were looking for. Sometimes xargs will give an error if the argument list is too long.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.