LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash script to update Debian type systems, a couple of questions (https://www.linuxquestions.org/questions/programming-9/bash-script-to-update-debian-type-systems-a-couple-of-questions-913593/)

k3lt01 11-15-2011 01:02 AM

Bash script to update Debian type systems, a couple of questions
 
Hi everyone

I have written a script to update Debian type systems and it works until the end where it just stops. I also have it installing Debdelta so it can use debdelta to minimise download times.

My questions are, can I get the script to work out if it needs to install Debdelta and then continue on if it doesn't?
Also can anyone see why it just stops at the end without actually upgrading?

Code:

#!/bin/bash
# A script to update package lists, creates debs from available deltas
# and upgrade the system without adding or removing anything.
echo "This script relies on debdelta being install on your system for it to
  work effectively"
read -p "Do you wish to install debdelta? (Y/n)"
        if [ "$REPLY" = "n" -o "$REPLY" = "N" ]; then
                echo "closing now"
                sleep 5
                exit 1
        fi
        if [ "$REPLY" = "y" -o "$REPLY" = "Y" ]; then
                echo
                echo "This script requires super-user access to continue."
                echo 'Checking for super-user access...'
                echo
                # Temporarily set sudo timeout to 360 mins
                echo "Defaults passwd_timeout=360" | sudo tee -a /etc/sudoers > /dev/null
                echo -en $WHITE "Access Granted." $GRAY

                echo "installing debdelta now"
                sudo aptitude update
                sudo aptitude install debdelta
                read -p "debdelta installed. Do you wish to continue? (Y/n)"
                        if [ "$REPLY" = "n" -o "$REPLY" = "N" ]; then
                        echo "closing now"
                        sleep 5
                        exit 1
                fi
                if [ "$REPLY" = "y" -o "$REPLY" = "Y" ]; then
                        echo "starting update/upgrade now"
                        sudo aptitude update
                        sudo debdelta-upgrade
                        sudo aptitude safe-upgrade
                fi
        fi
fi


evo2 11-15-2011 01:10 AM

Hi,

you can use something like 'dpkg -l <package>' to find out if a given package is installed.
If you indent the script properly I think you'll see you've got an extra fi.

Cheers,

Evo2.

evo2 11-15-2011 01:14 AM

Opps, sorry, not 'dpkg -i', 'dpkg -s'.

Eg.
Code:

dpkg -s debdelta > /dev/null 2>&1
if [ "$?" != "0" ] ; then
  echo "Please install debdelta"
  exit 1
fi

Cheers,

Evo2.

k3lt01 11-15-2011 01:33 AM

Hi Evo
Thanks for your reply. I see how that would work on its own, yes I tried it after reading the man page (should have read that before lol) but I can't see how to add it to the script. Should I use grep or something similar?

evo2 11-15-2011 01:39 AM

Hi,

well, first test if it is installed then if it is not you can ask the user if they want to install it, or otherwise exit.

Something like:

Code:

dpkg -s debdelta > /dev/null 2>&1
if [ "$?" != "0" ] ; then
  echo "It seems debdelta is not installed.
  read -p "This script needs debdelta. Can I install it? y/n >"
  if [ "$REPLY" != "y" ] ; then
    exit 1
  fi
  sudo apt-get install debdelta
fi

Cheers,

Evo2.

grail 11-15-2011 01:44 AM

Quote:

I see how that would work on its own
I am not sure why you think it would work any differently in your script?

You can also make it a little simpler (as your using bash):
Code:

if ! dpkg -s debdelta > /dev/null 2>&1
then
  echo "Please install debdelta"
  exit 1
fi


k3lt01 11-15-2011 01:47 AM

Quote:

Originally Posted by evo2 (Post 4524312)
Hi,

well, first test if it is installed then if it is not you can ask the user if they want to install it, or otherwise exit.

[code]
dpkg -s debdelta > /dev/null 2>&1
if [ "$?" != "0" ] ; then
echo "It seems debdelta is not installed.
echo "This script needs debdelta. Can I install it?"

exit 1
fi

Shouldn't something be infront of dpkg so the script can use it? like if, read, fi, echo etc, that is what I am confused with.

k3lt01 11-15-2011 01:54 AM

Quote:

Originally Posted by grail (Post 4524315)
I am not sure why you think it would work any differently in your script?

Hi grail. I test things on their own before I try them with other things, it is how I work through things. It is the way I diagnose things that I don't know how to do. I'm basically sitting here teaching myself scripting.

Quote:

Originally Posted by grail (Post 4524315)
You can also make it a little simpler (as your using bash):
Code:

if ! dpkg -s debdelta > /dev/null 2>&1
then
  echo "Please install debdelta"
  exit 1
fi


Doesn't seem to want to work in the script

trappa01 11-15-2011 02:15 AM

Quote:

Shouldn't something be infront of dpkg so the script can use it? like if, read, fi, echo etc, that is what I am confused with.
No. It just runs the command and bins the output. The next line check the return code for the command. If the package is installed $?=0 . Otherwise $?=1.

The later version.
Code:

if ! dpkg -s debdelta > /dev/null 2>&1
then
  echo "Please install debdelta"
  exit 1
fi

does the same thing but compares the result of the command at execution.

k3lt01 11-15-2011 02:42 AM

Ok the adddition is now working, sort of, in the script. One thing is wrong, everytime I run it it still wants to install debdelta which is already installed.

k3lt01 11-15-2011 03:12 AM

I think I know what's going wrong with the debdelta installation, I haven't given any options in the script so it is still going to install debdelta because the script says to. There isn't any conditional to say hey if it isn't installed install it but if it is installed move to the next section.

I'll have to do some more reading, I don't know at the moment how to use the /dev/null to say move to the next section cause you already have debdelta or if I need to modify the next section.

EDIT: Also what's the proper format for indentation? I have been using the tab key.

grail 11-15-2011 03:50 AM

Indentation is a personal thing and tab is fine if you like the look of it :)

As for how to utilise the code simply place install part inside if.

trappa01 11-15-2011 03:52 AM

Don't worry too much about /dev/null for your script. It is only a "bin" device that acts like a black hole. If you run a command but don't want the output clogging up your screen, you send the output to /dev/null. This does not change the result of the command, just the output. The example also adds 2>$1 which says to also send stderr to /dev/null.

k3lt01 11-15-2011 04:21 AM

Thanks guys, I have the debdelta part working perfectly now but the upgrade still isn't working as it should. There is a error at the end but it flashes by and then the terminal closes. Is there a way to create a readable log file from what is on the terminal screen?

My current file looks like this
Code:

#!/bin/bash
# A script to update package lists, creates debs from available deltas
# and upgrades the system without adding anything that is not required or
# removing something that is required.
# Created by me so I could teach myself scripting
# with help from trappa01, grail, and evo2 from LinuxQuestions.
if ! dpkg-query -l debdelta = i > /dev/null 2>&1
then
        echo "This script requires super-user access to continue."
        echo 'Checking for super-user access...'
        echo
        # Temporarily set sudo timeout to 360 mins
        echo "Defaults passwd_timeout=360" | sudo tee -a /etc/sudoers > /dev/null
        echo -en $WHITE "Access Granted." $GRAY
        echo "starting update/upgrade now"
        sudo aptitude update
        sudo debdelta-upgrade
        sudo aptitude safe-upgrade
        fi
fi
else
        echo "It seems debdelta is not installed."
        read -p echo "This script relies on debdelta being installed /non your system for it to work effectively"
        read -p "Do you wish to install debdelta? (Y/n)"
        if [ "$REPLY" = "n" -o "$REPLY" = "N" ]; then
                echo "closing now"
                sleep 5
                exit 1
        fi
        if [ "$REPLY" = "y" -o "$REPLY" = "Y" ]; then
                echo
                echo "installing debdelta now"
                sudo aptitude update
                sudo aptitude install debdelta
                read -p "debdelta installed. Do you wish to continue? (Y/n)"
                        if [ "$REPLY" = "n" -o "$REPLY" = "N" ]; then
                        echo "closing now"
                        sleep 5
                        exit 1
                fi
                if [ "$REPLY" = "y" -o "$REPLY" = "Y" ]; then
                        echo "starting update/upgrade now"
                        sudo aptitude update
                        sudo debdelta-upgrade
                        sudo aptitude safe-upgrade
                fi
        fi
fi


grail 11-15-2011 04:30 AM

Well, evo pointed out in his first post that you have to look at how many times you open / close your if statements.

Also I cannot understand how you new if statement works?
Code:

if ! dpkg-query -l debdelta = i > /dev/null 2>&1
Remembering that a script just helps you from typing a lot of stuff at the command line, what do you get when you run the following on the command line:
Code:

dpkg-query -l debdelta = i
Because I get errors, which of course are hidden by outputting to /dev/null as pointed out by trappa01

k3lt01 11-15-2011 04:35 AM

I put it in the terminal and it said no output matching. Should have tested that better than I did. Stupid thing is the script works through that ok for some reason. I'll take it out and see what happens.

grail 11-15-2011 04:39 AM

It will always work because you have said when this command fails, which it will every time, to then run what is inside the if statement.

Also, your system must be quite different to mine, here is what I get:
Code:

$ dpkg-query -l debdelta = i
dpkg-query: error: package name in specifier '=' is illegal: must start with an alphanumeric character

Which is nothing along the lines of 'no output matching'??

k3lt01 11-15-2011 04:59 AM

Sorry if I'm slow in replying there's a huge storm outside and it is knocking my net access about a bit.

Here is the exact out from that query
Code:

root@michael-laptop:/home/michael# dpkg-query -l debdelta = i
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name          Version        Description
+++-==============-==============-============================================
un  debdelta      <none>        (no description available)
No packages found matching =.
No packages found matching i.
root@michael-laptop:/home/michael#

The man oage says
Quote:

COMMANDS
-l, --list [package-name-pattern...]
List packages matching given pattern. If no package-name-pattern
is given, list all packages in /var/lib/dpkg/status, excluding
the ones marked as not-installed (i.e. those which have been
previously purged). Normal shell wildchars are allowed in pack-
age-name-pattern. Please note you will probably have to quote
package-name-pattern to prevent the shell from performing file-
name expansion. For example this will list all package names
starting with “libc6”:

dpkg-query -l 'libc6*'

The first three columns of the output show the desired action,
the package status, and errors, in that order.

Desired action:
u = Unknown
i = Install
h = Hold
r = Remove
p = Purge

Package status:
n = Not-installed
c = Config-files
H = Half-installed
U = Unpacked
F = Half-configured
W = Triggers-awaiting
t = Triggers-pending
i = Installed
and that is where I got it from. I assumed if the response come back as i it would tell the script it was installed.

EDIT: This is the query without the -i
Code:

root@michael-laptop:/home/michael# dpkg-query -l debdelta
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name          Version        Description
+++-==============-==============-============================================
un  debdelta      <none>        (no description available)
root@michael-laptop:/home/michael#

Problem is I know from synaptic that it is installed and I've used it today already

trappa01 11-15-2011 05:09 AM

grail is right. You don't need the "= i" in the statement at all.

if ! dpkg-query -l debdelta > /dev/null 2>&1 will give you a true/false return code (0 or 1). If the return code is 1 (false) then the script will go into the "then" block (this is because of the ! after the if).

What is probably happening in your script is that you are getting an error due to the "= i" and therefore a return code of non-zero. This will always execute the "then" block.

As for your question about seeing the output, you can execute your script using "script > log.txt"

trappa01 11-15-2011 05:13 AM

Try using -s instead of -l

k3lt01 11-15-2011 05:39 AM

I understand the mistake I made.

Quote:

Originally Posted by trappa01 (Post 4524475)
As for your question about seeing the output, you can execute your script using "script > log.txt"

Gotta love computers, all the output is going to the txt file except for this snippet
Code:

root@michael-laptop:/home/michael/Desktop# ./update_upgrade > log.txt
y
Reading changelogs...
Extracting templates from packages: 100%
./update_upgrade: line 52: syntax error near unexpected token `fi'
./update_upgrade: line 52: `fi'
root@michael-laptop:/home/michael/Desktop#

Anyway the process all worked as it should just then, apart from not being able to see what was happening on the terminal. I don't know if that is normal behaviour but if it is how can I change it to post everything on the terminal so I can see what is happening and also keep a log for later reference so I can see how much download debdelta is saving.

k3lt01 11-15-2011 05:42 AM

Quote:

Originally Posted by trappa01 (Post 4524478)
Try using -s instead of -l

I'll do that tomorrow it's nearly 11pm here now, good thing I don't have to go to work this week lol.

Thank you all again, I appreciate your assistance.

trappa01 11-15-2011 06:40 AM

Quote:

Gotta love computers, all the output is going to the txt file except for this snippet
Sorry, I should have been more clear. "./update_upgrade > log.txt" will send the stdout to log.txt but not stderr.
Run with "./update_upgrade > log.txt 2>&1" so that you get both sent to your log file.

As for the error, its probably still a mismatch between the if statements and their corresponding fi's .

evo2 11-15-2011 07:47 PM

Hi,

ok, I couldn't help myself, here is a version of the script (with very verbose comments). Note that I _did_not_ screw around with the sudo setup since I think doing such a thing is prone to causing errors.

Code:

#!/bin/bash

#
# Check if debdelta is installed
#
dpkg -s debdelta > /dev/null 2>&1
# The return value of the last command is stored in $?
# If the above commands return value is 0, then debdelta is installed
if [ "$?" != "0" ] ; then
    echo "It seems debdelta is not installed."
    read -p "This script needs debdelta. Can I install it? y/n >"
    if [ "$REPLY" != "y" ] ; then
        echo "Can not run without debdelta. Exiting."
        exit 1
    fi
    # Install debdeta and exit the script if there is an error
    sudo apt-get install debdelta || exit 1
fi
echo "Ok, debdelta is installed."

#
# Check if the user really wants to do the upgrade
#
read -p "Do you really want to do the upgrade? y/n >"
if [ "$REPLY" != "y" ] ; then
    echo "Ok, not upgrading."
    exit 0
fi

#
# Do it. Only run the next command if the previous command exited cleanly
#
echo "Starting upgrade..."
sudo aptitude update && sudo debdelta-upgrade && sudo aptitude safe-upgrade

Please note, that this script is not tested, and (although it is a
very simple) therefore it may contain undocumented features (AKA bugs).

Cheers,

Evo2.

k3lt01 11-15-2011 08:10 PM

Hi Evo, thanks for this I appreciate your input. I'll take the script for a test drive and see how it goes.

The script I wrote has worked but only when I had it output to the log and when very little if anything showed in the terminal. This is something I don't understand but am looking at today. I also believe that logging the process to file would be a good feature so people can see how much download they are saving using debdelta, how would I achieve that with your script? It needs to be a part of the script itself not part of the command to run it.

Thanks again for your help and patience. I have only tried scripting once before (I have a small 1 line script that removes duplicate entries from a host file) a few years ago so it's a huge learning curve for me.


All times are GMT -5. The time now is 01:57 PM.