How to use dpkg in silent mode - bash

I try to test if some packages are installed in my script before run it.
To do that by the dpkg command. This is my code :
dpkg -s dialog
dialogStatut=$?
if [ "$dialogStatut" -eq 1 ]; then
//Install package
fi
I would like to make dpkg in silent mode (without echo).
I have tried to put >&- 2>&- behind the command but if i do that the value is always 2 (if dialog is installed or not).
I have don't find solution in man dpkg.
What is the best way to do that?

You are looking for 2> /dev/null
if ! dpkg -s dialog 2> /dev/null; then
...
fi
Consider just exiting your script to let dialog be installed explicitly rather than making your script responsible for doing so.

I would do something like
dpkg -l dialog &>/dev/null || apt-get install dialog
The speciality with OR(||) if the first condition evaluates to true(ie an exit status of zero), then the second condition will not be evaluated.

Related

Why doesn't testing exit status work when output is redirected?

I have been testing bash and found the following code:
#!/bin/bash
[[ `which pacman` ]] && echo pacman
[[ `which apt-get` ]] && echo apt-get
It will test what package manager is installed and echo it.
On some systems, a failed which command prints the error to stderr. I want to suppress all output from the which command.
So I came up with the following code:
#!/bin/bash
[[ `which pacman >/dev/null 2>&1` ]] && echo pacman
[[ `which apt-get >/dev/null 2>&1` ]] && echo apt-get
But this doesn't output anything. When I run each command on the command line like this:
which pacman >/dev/null 2>&1 && echo $?
On a system with pacman, it prints 0 which it should. The && also proves that the previous command succeeded.
So why doesn't the redirection code work like it does on the command line? What can I add to the script to make it work?
This is really confusing to me, as I have never had this type of problem before. Usually, any command that works on the command line should also work in a bash script, shouldn't it?
[[ ... ]] without a specified test runs [[ -n ... ]]. In this case, it tests whether the captured output is non-empty. But if you redirect everything to /dev/null, the output is indeed empty!
You don't need to capture the output. which should already return a non-zero status when it cannot find the file to execute.
which pacman &> /dev/null && echo pacman

Is there a way for me to get specific words from an output of a command in bash?

For example, when running the dpkg command,
dpkg -s autofs
I would get an output like
dpkg-query: package 'autofs' is not installed and no information is available
But I just want to get the
not installed
part so that I can further use it for my script. Is there a command that can help me with it?
First of all, the words not installed are locale specific, so it will fail with anything but English locales. It is also non-predictable because it is not a published API Application Programming Interface.
So, even with some precautions, do not use this:
LC_MESSAGES=C dpkg-query --status autofs 2>&1 | grep -o 'not installed'
Check the return status of the dpkg-query command instead:
#!/usr/bin/env sh
package='autofs'
if dpkg-query --status "$package" >/dev/null 2>&1; then
printf 'Package %s is installed!\n' "$package"
else
printf 'Package %s is not installed!\n' "$package"
fi

Bash script from URL: return code when curl fails?

One of the solutions to execute a bash script directly from a URL is:
bash <(curl -sS http://1.1.1.1/install)
The problem is that when curl fails to retrieve the url, bash get's nothing as input and it ends normally (return code 0).
I would like the whole command to abort with the return code from curl.
UPDATE:
Two possible solutions:
curl -sS http://1.1.1.1/install | bash; exit ${PIPESTATUS[0]}
or:
bash <(curl -sS http://1.1.1.1/install || echo "exit $?")
The last one is kind of hackish (but shorter)
Try this to get curl's returncode:
curl -sS http://1.1.1.1/install | bash
echo ${PIPESTATUS[0]}
Use a temporary file.
trap 'rm "$install"' EXIT
installer=$(mktemp)
curl ... > "$installer" || exit
# Ideally, verify the installer *before* running it
bash "$installer"
Here's why. If you simply pipe whatever curl returns to bash, you are essentially allowing unknown code to execute on your machine. Better to make sure that what you are executing isn't harmful first.
You might ask, how is this different from using a pre-packaged installer, or an RPM, or some other package system? With a package, you can verify via a checksum provided by the packager that the package you are about to install is the same one they are providing. You still have to trust the packager, but you don't have to worry about an attacker modifying the package en route (man-in-the-middle attack).
You could save the output of the curl command in a variable and execute it only if the return status was zero. It might not be so elegant, but it's more compatible to other shells (doesn't rely on $PIPESTATUS, which isn't available on many shells):
install=`curl -sS http://1.1.1.1/install`
if [ $? -ne 0 ]; then
echo "error"
else
echo "$install" | bash
fi

Bash Centos7 "which" command

I realize this might be a dumb question but I have a Centos-7 minimal server install and the "which" command does not exist or is missing.
I have a script that needs it and I cannot find out what the yum package is that installs it.
The code is below and is from a make file.
which grep > /dev/null 2> /dev/null
if test "$?" != "0"
then
echo "\"grep\" command not found."
echo "Installation is aborted."
exit 1
fi
Any help would be appreciated... this is difficult if not impossible to google
To find a package in CentOS, use yum whatprovides:
yum whatprovides *bin/which
In this particular case, the package is called which, so
yum install which
should pull it in.
Instead of which command you can use type command.
type grep > /dev/null 2> /dev/null
if test "$?" != "0"
then
echo "\"grep\" command not found."
echo "Installation is aborted."
exit 1
fi

Can I make bash report errors only errors at the end of a script?

I have a bash script which sequentially executes many tasks.
However, because I do not want to see simple status messages (such as the long output of yum -y update), I ignored all those messages using:
#!/bin/bash
(
yum -y update
cd /foo/bar
cp ~/bar /usr/bin/foo
...
...
) > /dev/null
This does the job just fine, but what if something went wrong, like cp failed to copy some file? If this happens, I would like to catch the error and exit immediately, before the process continues.
How can I exit the process and show the related error? Normally,
an if/else clause would have to be used, like this:
#!/bin/bash
yum -y update
if [ $? -ne 0 ]; then
echo "error "
exit 1
fi
But the problem with this approach is that it would show the process; therefore, I would have to use > /dev/null on each line; more importantly, if I had more than 100 things to do, then the I would have to use many if/else statements.
Is there a convenient solution for this?
Rather than running your commands in (...) use set -e OR bash -ec to execute them:
bash -ec 'set -e
yum -y update
cd /foo/bar
...
...
cp ~/bar /usr/bin/foo' > /dev/null 2> errlog
OR using set -e:
(
set -e
yum -y update
cd /foo/bar
...
...
cp ~/bar /usr/bin/foo
) > /dev/null 2> errlog
-e option will make sure to exit the sub shell as soon as an error occurs.

Resources