Pipe Breaks CLI Output, Shell Scripting Advice Wanted

I want to install packages from a commented list, so making use of classic GNUnix programs like sed & xargs I whipped this up:

sed 's/.#.*//;/^$/d' /path/to/aptlist | xargs sudo apt-get install -y

, which generally works perfectly fine, except for that | breaks most installers that need to draw an interactive text user interface (TUI) & seemingly brings the whole command to a screeching halt.

Relatedly but less seriously, I have a similar command for Flatpaks:

sed 's/.#.*//;/^$/d' /path/to/flatlist | xargs flatpak install flathub -y

, again | corrupts text output of the installation progress (like w/ TUIs) & spams a bunch of garbled text ready to be input once the command is done, seemingly halting any script this command is in, I can show that part here:

Installing 3/3… ████████████████████ 100%  5.8 MB/s  00:00^[[53;68R^[[53;68R1R
^[[53;77Ruser@system:~$ ;1R;1R;17R;62R;51R;51R;51R;61R;61R;62R;61R;61R;61R;61R;61R;61R;61R;79R;62R;51R;51R;69R;62R;51R;51R;51R;61R;61R;62R;61R;61R;61R;61R;61R;61R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;68R;77R

This has been driving me crazy. If anyone here more knowledgeable than me w/ bash shell scripting can lend their expertise–& help me find a solution–I would be very grateful! Feel free to ask questions.

Your sed regex is incorrect, do you have a sample of the package list? The period in front of # results in it not matching on # presuming the first character of the line is a #. The replacement part of that is empty and if it were to match would delete the entire line since you’re matching on the rest of the line as well.

If there is a space between the # and package name, I think you want sed 's/#.//;/^$/d'

That is not what’s causing the problem, & I’ve never had any problems caused by the regex as it currently is, but thank you for telling about that.

The lists are formatted like this:

## Comment
package #Comment
another-package #Comment

Gotcha, I usually think of # at the start when someone says commented lines.

What about apt-get install -y $(sed 's/.#.*//;/^$/d' list.txt)?

1 Like

I’ll give it a go & get back to you ASAP!

1 Like

I’m pretty sure xargs runs the apt-get command individually for each package, kind of like a for-each loop but based off spacing and line returns. The above will run apt-get once for all the packages.

1 Like

Thanks for that xargs explanation.

Above structure worked perfectly w/o any of the issues w/ either package manager I described in OP. I really should’ve thought of using subshell as soon as I added sed streaming to remove comments. This command is much simpler & just works.

Thank you @2FA!

1 Like

It’s great that you’ve got a solution, but IMO this kind of problem is better tackled step by step. Run the sed first, output to a file, or more simply, copy the file and make the changes using the editor you’re most skilled with. (It’s hard enough getting regexes right without having to remember the vagaries of different versions; sed != grep != awk != vim != javascript). Having checked the results, then you can tackle the quoting problems xargs will cause. Those problems can be a pain, so editing the file to put a command on each line (“sudo apt-get install -y” in this case) steps around them quickly.

1 Like

Not by default. You’d need to invoke it as xargs -L1 to do that.

From the man page:

   The command line for command is built up until it reaches a system-defined limit (unless the -n and -L
   options are used).  The specified command will be invoked as many times as necessary  to  use  up  the
   list  of  input  items.   In  general, there will be many fewer invocations of command than there were
   items in the input.  This will normally have significant performance benefits.  Some commands can use‐
   fully be executed in parallel too; see the -P option.