2

I set up a pipe returning the name of a package I'd like to install using apt-get:

... | xargs -I _ sudo apt install _

However, apt-get can't read from stdin in this case and exits with:

Do you want to continue? [Y/n] Abort.

I know about the -y flag to install the package without user confirmation, but I'd like to actually see the confirmation.

Is there a way to forward the package name to apt-get while still allowing it to read from stdin?

Putting apt-get on the left side of the whole command is not an option since I don't want apt-get to be executed if an ealier command in the pipe is aborted, using the set -o pipefail option.

5
  • Would it work if you put the output into an array and then loop over it?
    – pfnuesel
    Commented Feb 8, 2018 at 14:51
  • Using echo "Please enter something." | xargs -I _ echo _; read, I see the output and it requests the read. I don't see how apt would do something else? Or am I assuming something wrong?
    – Stefan M
    Commented Feb 8, 2018 at 15:32
  • @StefanM In your case, you're running read outside the pipe. In the question, apt runs inside the pipe. Try something like echo foo | xargs sh -c "read x; echo $x"
    – ilkkachu
    Commented Feb 8, 2018 at 15:34
  • @ilkkachu Yes, you're right. The ; seperates the read from the rest. ;)
    – Stefan M
    Commented Feb 8, 2018 at 15:37
  • @StefanM It would be okay to assign the output of the pipe without the last apt-get stage to a variable and then execute apt-get on the value of the variable if it is set. Am I correctly assuming that the variable won't be set if the pipe fails?
    – danijar
    Commented Feb 8, 2018 at 15:51

2 Answers 2

2

pipefail doesn't stop the right-hand side of the pipeline from running, the whole pipe runs simultaneously, as usual. Try e.g.

$ set -o pipefail
$ false | echo foo
foo

It's the use of xargs that may or may not prevent running apt here, if it gets no input. Without -r or -I it would still run the command at least once.

But you could work around that by capturing the output with a command substitution and then running apt or not, based on the result:

if packages=$(somecmd...) && [ "$packages" ] ; then
    set -f
    sudo apt install $packages
fi

Package names should not have any whitespace, so using $packages unquoted should work (assuming the default value of $IFS; they probably can't contain glob characters either, so set -f may be unnecessary).

2

With the GNU implementation of xargs (the one typically found on systems that also have an apt command) and a shell like ksh93/zsh/bash with support for process substitution, you can do:

sudo xargs -I _ -ra <(cmd) apt install _

instead of:

cmd | xargs -I _ sudo apt install _

Note that it would probably make more sense to pass all the packages at once to apt rather than calling one apt per package.

sudo xargs -d '\n' -ra <(cmd) apt install

(-d being another GNU extension)

In any case like in the pipeline version, with or without pipefail, that will run sudo regardless of whether cmd succeeds or not since sudo and cmd are started at the same time and run concurrently.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .