A universal bash script for installing with apt-get and yum - linux

I'm trying to write a simple bash wrapper which abstracts yum and apt-get. Basically so we can do something like universal-install curl Here is what I have so far:
# universal-install
package=$1
apt=`command -v apt-get`
yum=`command -v yum`
if [ -n "$apt" ]; then
apt-get update
apt-get -y install $package
elif [ -n "$yum" ]; then
yum -y install $package
else
echo "Err: no path to apt-get or yum" >&2;
exit 1;
fi
Are there any errors or improvements/optimizations that can be made?

Take a look at how pacapt detects the OS:
# Detect package type from /etc/issue
_found_arch() {
local _ostype="$1"
shift
grep -qis "$*" /etc/issue && _OSTYPE="$_ostype"
}
# Detect package type
_OSTYPE_detect() {
_found_arch PACMAN "Arch Linux" && return
_found_arch DPKG "Debian GNU/Linux" && return
_found_arch DPKG "Ubuntu" && return
_found_arch YUM "CentOS" && return
_found_arch YUM "Red Hat" && return
_found_arch YUM "Fedora" && return
_found_arch ZYPPER "SUSE" && return
[[ -z "$_OSTYPE" ]] || return
# See also https://github.com/icy/pacapt/pull/22
# Please not that $OSTYPE (which is `linux-gnu` on Linux system)
# is not our $_OSTYPE. The choice is not very good because
# a typo can just break the logic of the program.
if [[ "$OSTYPE" != "darwin"* ]]; then
_error "Can't detect OS type from /etc/issue. Running fallback method."
fi
[[ -x "/usr/bin/pacman" ]] && _OSTYPE="PACMAN" && return
[[ -x "/usr/bin/apt-get" ]] && _OSTYPE="DPKG" && return
[[ -x "/usr/bin/yum" ]] && _OSTYPE="YUM" && return
[[ -x "/opt/local/bin/port" ]] && _OSTYPE="MACPORTS" && return
command -v brew >/dev/null && _OSTYPE="HOMEBREW" && return
[[ -x "/usr/bin/emerge" ]] && _OSTYPE="PORTAGE" && return
[[ -x "/usr/bin/zypper" ]] && _OSTYPE="ZYPPER" && return
if [[ -z "$_OSTYPE" ]]; then
_error "No supported package manager installed on system"
_error "(supported: apt, homebrew, pacman, portage, yum)"
exit 1
fi
}
As you can see it first checks /etc/issue, then failing that the script looks for the associated executable file for each package manager.
But heck, why not just use pacapt, instead of rolling your own?

If you're going to do this, why require the user to tell the script which tool to use?
#!/bin/bash
# Find our package manager
if VERB="$( which apt-get )" 2> /dev/null; then
echo "Debian-based"
elif VERB="$( which yum )" 2> /dev/null; then
echo "Modern Red Hat-based"
elif VERB="$( which portage )" 2> /dev/null; then
echo "Gentoo-based"
elif VERB="$( which pacman )" 2> /dev/null; then
echo "Arch-based"
else
echo "I have no idea what I'm doing." >&2
exit 1
fi
if [[ 1 -ne $# ]]; then
echo "Syntax: $0 PACKAGE"
exit 1
fi
$VERB "$1"
exit $?
Slightly better would to to look at /etc/issue to see what your distribution is and behave accordingly.

I was looking for a one-liner to install a package and couldn't find any so this was my final version:
if [ "" == "`which unzip`" ]; then echo "Unzip Not Found"; if [ -n "`which apt-get`" ]; then apt-get -y install unzip ; elif [ -n "`which yum`" ]; then yum -y install unzip ; fi ; fi
It's specific for the unzip package, but can be altered to any other package that is available on apt-get/yum.
Hope this will help someone :)

#!/bin/bash
# file: src/bash/aspark-starter/install-prerequisites-for-aspark-starter.sh
# caveat package names are for Ubuntu !!!
set -eu -o pipefail # fail on error , debug all lines
# run as root
[ "${USER:-}" = "root" ] || exec sudo "$0" "$#"
echo "=== $BASH_SOURCE on $(hostname -f) at $(date)" >&2
echo installing the must-have pre-requisites
while read -r p ; do
if [ "" == "`which $p`" ];
then echo "$p Not Found";
if [ -n "`which apt-get`" ];
then apt-get install -y $p ;
elif [ -n "`which yum`" ];
then yum -y install $p ;
fi ;
fi
done < <(cat << "EOF"
perl
zip unzip
exuberant-ctags
mutt
libxml-atom-perl
postgresql-9.6
libdbd-pgsql
curl
wget
libwww-curl-perl
EOF
)
echo installing the nice-to-have pre-requisites
echo you have 5 seconds to proceed ...
echo or
echo hit Ctrl+C to quit
echo -e "\n"
sleep 6
echo installing the nice to-have pre-requisites
while read -r p ; do
if [ "" == "`which $p`" ];
then echo "$p Not Found";
if [ -n "`which apt-get`" ];
then apt-get install -y $p ;
elif [ -n "`which yum`" ];
then yum -y install $p ;
fi ;
fi
done < <(cat << "EOF"
tig
EOF
)

Related

Creating an RPM with CMake will result in unusable system

Currently I am moving my packaging from a bunch of weird scripts into CMake using CPack. The Debian and TGZ work really nice but the RPM is giving me troubles... When I install the RPM that has been created on openSUSE 15.1 then it will result in an unusable system (no even ls can be executed anymore and I cannot dig into why as of not beeing able to open a konsole or something).
Here is my CPack code (ive stripped anything with DEB and TGZ for readability):
set(CPACK_GENERATOR "DEB;TGZ;RPM")
# Common packaging params
set(CPACK_PACKAGE_NAME "mytool")
set(VERSION "${ver_maj}.${ver_min}.${ver_build}")
set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_SET_DESTDIR true)
# RPM packaging params
set(CPACK_RPM_PACKAGE_SUMMARY "Summary")
set(CPACK_RPM_PACKAGE_NAME "mytool")
set(CPACK_RPM_PACKAGE_VERSION "${VERSION}")
set(CPACK_RPM_PACKAGE_LICENSE "Proprietary")
set(CPACK_RPM_PACKAGE_GROUP "Applications/Internet")
set(CPACK_RPM_PACKAGE_VENDOR "me, myself and I")
set(CPACK_RPM_PACKAGE_URL "https://myurl555.com/")
set(CPACK_RPM_PACKAGE_DESCRIPTION "MyDesc")
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/make/rpm/post")
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/make/rpm/postun")
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/make/rpm/preun")
The post script:
if [ -x %{_bindir}/gtk-update-icon-cache-2.0 ]; then
%{_bindir}/gtk-update-icon-cache-2.0 %{_datadir}/icons/hicolor > /dev/null 2>&1 || true
fi
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache %{_datadir}/icons/hicolor > /dev/null 2>&1 || true
fi
SYSTEMD=`pidof systemd || echo '0'`
if [ "${SYSTEMD}" != "0" ]; then
if [ -e /etc/systemd/system/mytool.service ]; then
rm /etc/systemd/system/mytool.service
fi
cp /usr/share/mytool/files/systemd/mytool.service /etc/systemd/system/mytool.service
systemctl daemon-reload
systemctl enable mytool
fi
service mytool start
if [ -x %{_bindir}/update-desktop-database ]; then
%{_bindir}/update-desktop-database > /dev/null 2>&1 || true
fi
postun:
if [ -x %{_bindir}/gtk-update-icon-cache-2.0 ]; then
%{_bindir}/gtk-update-icon-cache-2.0 %{_datadir}/icons/hicolor > /dev/null 2>&1 || true
fi
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache %{_datadir}/icons/hicolor > /dev/null 2>&1 || true
fi
SYSTEMD=`pidof systemd || echo '0'`
if [ "${SYSTEMD}" != "0" ]; then
systemctl daemon-reload
fi
preun:
service mytool stop > /dev/null 2>&1 || true
SYSTEMD=`pidof systemd || echo '0'`
if [ "${SYSTEMD}" != "0" ]; then
systemctl disable mytool > /dev/null 2>&1 || true
rm /etc/systemd/system/mytool.service
fi
I cannot see any reason why something like this happens. What happens to the system is that when using alt+f2 and running for example konsole then it will tell me that it cannot make konsole executable. The executable /usr/bin/konsole is still there, the groups of the user did not change, etc.

How can I check that program was installed successfully on linux?

I have .bin file, that contains a lot of scripts, that install program on Ubuntu and after installing via terminal
sudo chmod u+x myprogram.bin
./myprogram
I have it in /usr/bin/myprogram.
I need to write the program, which checks if some program was installed correctly to the system. How can I do that ?
Any one of the followings should work
$ command -v foo >/dev/null 2>&1 && echo "installed" || echo "not installed"
$ type foo >/dev/null 2>&1 && echo "installed" || echo "not installed"
$ hash foo >/dev/null 2>&1 && echo "installed" || echo "not installed"
In your case you may use
$ command -v /usr/bin/myprogram >/dev/null 2>&1 && echo "installed" || echo "not installed"
or else you can create function like below
#!/usr/bin/env bash
installed()
{
command -v "$1" >/dev/null 2>&1
}
# and then
if installed ls; then
echo 'ls exists'
else
echo 'ls not installed'
fi
Examples :
$ command -v ls >/dev/null 2>&1 && echo "installed" || echo "not installed"
installed
$ command -v foo >/dev/null 2>&1 && echo "installed" || echo "not installed"
not installed
If you already know the full path to the application/program then any one of the following should work
$ test -x /bin/ls && echo 'installed' || echo 'not installed'
installed
$ [ -x /bin/ls ] && echo 'installed' || echo 'not installed'
installed

Bash if condition to check if a ubuntu package has a newer version?

I need a bash line to check if a ubuntu package needs an upgrade or not.
For example, I want to check if the package 'firefox' needs an upgrade using dpkg or apt-get commands.
Hypthetical Example:
# Hypothetical example pseudo-code
if [[ $(firefox_needs_upgrade) ]]; then echo "Firefox needs upgrading";fi
This should work for you:
#!/bin/bash
PACKAGE="firefox"
TMP_FILE="/tmp/upgrade_list"
apt-get -yqq update
apt-get -sqq upgrade | grep Inst > ${TMP_FILE}
grep -qi ${PACKAGE} ${TMP_FILE}
if [ $? == 0 ]
then
echo "${PACKAGE} needs to be upgraded"
fi
Following command would help you :-
/usr/lib/update-notifier/apt-check --human-readable
or
cat /var/lib/update-notifier/updates-available
For more details you can check the link below :-
https://askubuntu.com/questions/49958/how-to-find-the-number-of-packages-needing-update-from-the-command-line
Thanks & Regards,
Alok Thaker
Bash function:
apt_needs_upgrade() {
NEEDS_UPGRADE=$(/usr/lib/update-notifier/apt-check -p 2>&1 >/dev/null | grep "^$1$" | wc -l)
if [ "$NEEDS_UPGRADE" == 1 ]; then
return 0; # 0 means true in bash!!!
else
return 1; # false
fi;
}
Use it:
if apt_needs_upgrade "firefox"; then
echo "Needs upgrading"
else
echo "No need to upgrade"
fi;
Ok edited my answer with a tested code. It's maybe a more pretty way to do it :
#retrieving info about the package
dpkg -l $1 >/dev/null
if [ $? -ne 0 ]
then
echo "$1 not installed or issue retrieving informations"
exit
else
#We check if pkg is upgradable
UPGRADABLE=$(apt-get -s upgrade -u | egrep -c "^Conf $1 |^Inst $1 ")
if [ $UPGRADABLE -gt 0 ]
then
echo "$1 need an upgrade"
else
echo "$1 up to date"
fi
fi
usage :
# /tmp/check.sh openssh-server
openssh-server need an upgrade

Error in shell script for detecting packages on system

I wrote a shell script for detecting whether a package is installed or not. My script should write its name and status if it's installed. I can't figure out any problem with my code but when I run it, it doesn't execute the commands under if [ $? == 0 ] condition.
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
fi
But the most weird thing to me is that it works if I add an echo after if statement. Looks like that:
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
echo hi
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
fi
So if I add an echo -n to right position in my code it will work as I want. But I just want to know what is wrong with first one?
I think in general you could be more deliberate about your return code handling. You are making assumptions about what $? is referring to that may not be valid depending on your program flow, and regardless, make the program harder to read and understand.
#!/bin/bash
dpkg -s $# &> /dev/null
installed=$?
if [ $installed -eq 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
else
echo -e "Package \033[0;31mNOT\033[0m found." >&2
fi
$? is the return status of the last executed command. 0 is successful, 1 or anything else is an error. Note:
dpkg -s python &> /dev/null # returns 0 (OK, true)
# $? equals 0 now
[ #? == 1 ] # false # returns 1 (error)
# $? equals 1 now
[ #? == 0 ] # false # returns 1 (error)
When you put echo, it works:
dpkg -s python &> /dev/null # returns 0 (OK, true)
# $? equals 0 now
[ #? == 1 ] # false # returns 1 (error)
# $? equals 1 now
echo hi # returns 0 (OK)
# $? equals 0 now
[ #? == 0 ] # true # returns 0 (OK)
You could save $? to a variable, but you don't really need the if inside the else since you already checked if #? == 1 so just put your code inside else:
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 1 ]; then
echo -e "Package \033[0;31mNOT\033[0m found." >&2
else
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
fi
If you are worried of other possible return statuses of $? (greater than one). You could rewrite your script to
#!/bin/bash
if [ "$1" == "" ]; then
echo "Please hold the line."
else
dpkg -s $# &> /dev/null
fi
if [ $? == 0 ]; then
for i in $#; do
dpkg -s $i | grep Package
dpkg -s $i | grep Status
done
else
echo -e "Package \033[0;31mNOT\033[0m found." >&2
fi

Bash thinks input is incorrect when it is?

I have this script, but on line 51, when I answer "y", bash skips that and tells me to "answer y or n" (skips to line 58):
debianDeps() {
apt-get install git cmake build-essential liblua5.2-dev \
libgmp3-dev libmysqlclient-dev libboost-system-dev
}
fedoraDeps() {
yum install git cmake gcc-c++ boost-devel \
gmp-devel community-mysql-devel lua-devel
}
bsdDeps() {
cd /usr/ports/shells/bash && make install clean BATCH=yes
cd /usr/ports/devel/git && make install clean BATCH=yes
cd /usr/ports/devel/cmake && make install clean BATCH=yes
cd /usr/ports/lang/gcc47 && make install clean BATCH=yes
cd /usr/ports/lang/luajit && make install clean BATCH=yes
cd /usr/ports/devel/boost-libs && make install clean BATCH=yes
cd /usr/ports/math/gmp && make install clean BATCH=yes
cd /usr/ports/databases/mysql-connector-c && make install clean BATCH=yes
}
libInstall() {
echo "Libraries and Build Tools... Installed"
}
bsdBuild() {
echo "Building on FreeBSD"
mkdir build && cd build
CXX=g++47 cmake ..
echo "Build on $cpuCores threads with $coreBuild processes? (experimental but loads faster) y or n "
read $ans1_4
if [[ $ans1_4 = "y" ]]; then
echo -e $greenText"Building on $cpuCores threads with $coreBuild ."$none
make -j $coreBuild
elif [[ $ans1_4 = "n" ]]; then
echo -e $blueText"Building on a single thread."$none
make
else
echo "answer y or n"
echo -e $redText"Answer y or n"$none
fi
}
genBuild() {
echo "Building..."
mkdir build && cd build
cmake ..
echo "Build on $cpuCores threads with $coreBuild processes? (experimental but loads faster) y or n "
read $ans1_4
if [[ $ans1_4 = "y" ]]; then
echo -e $greenText"Building on $cpuCores threads with $coreBuild ."$none
make -j $coreBuild
elif [[ $ans1_4 = "n" ]]; then
echo -e $blueText"Building on a single thread."$none
make
else
echo -e $redText"Answer y or n"$none
fi
}
clean() {
mkdir objs/
mv *.o objs/
echo "There might be a few leftover files."
}
###
### Script starts here
###
#check if root
if [[ $EUID -ne 0 ]]; then
echo "You must be root to use this script, press enter to exit."
read end
exit 1
fi
#OS dependencies and other stuff
echo "Chose your Operating System. {Supported OS: Debian, Ubuntu, Fedora, CentOS, FreeBSD} "
read ans1
if [[ $ans1 = "Fedora" ]] || [[ $nas1 = "CentOS" ]]; then
echo -n "Should the script install dependencies? y or n"
read ans1_1
if [[ $ans1_1 = "y" ]]; then
fedoraDeps
elif [[ $ans1_1 = "n" ]]; then
break
else
echo "Answer 'y' or 'n' "
fi
elif [[ $ans1 = "Debian" ]] || [[ $ans1 = "Ubuntu" ]]; then
echo -n "Should the script install dependencies? y or n"
read ans1_1
if [[ $ans1_1 = "y" ]]; then
debianDeps
elif [[ $ans1_1 = "n" ]]; then
break
else
echo "Answer 'y' or 'n' "
fi
elif [[ $ans1 = "FreeBSD" ]]; then
echo -n "Should the script install dependencies? y or n"
read ans1_1
if [[ $ans1_1 = "y" ]]; then
bsdDeps
elif [[ $ans1_1 = "n" ]]; then
break
else
echo "Answer 'y' or 'n' "
fi
else
echo "Pick a valid OS"
fi
#Compiling here
echo -n "Are we on FreeBSD? y or n"
read ans1_2
if [[ $ans1_2 = "y" ]]; then
bsdbuild
elif [[ $ans1_2 = "n" ]]; then
genBuild
else
echo "Answer y or n"
fi
echo "Should the folder be cleaned? y or n"
read ans1_3
if [[ $ans1_3 = "y" ]]; then
clean
elif [[ $ans1_3 = "n" ]]; then
echo "Exiting..."
exit 1
else
echo "Answer y or n"
fi
read $ans1_4 should be read ans1_4 I made a little mistake there.

Resources