ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I am building a script to manually update my dovecot packages directly from dovecot repo , however this script does not do that job straight ahead .
First checks apt policy to see witch packages of dovecot are installed in system , and then write those packages names to a file .
I am posting here this part only of the code , but when i look into the logfile from apt and compare strings with IF statement i get "invalid arithmetic operator on my loop."
Code:
#!/bin/bash
basedir="/dovecot"
if [[ ! -d "$basedir" ]]
then
mkdir "$basedir"
mkdir "$basedir/update"
else
rm -f "$basedir/update/*.*"
rm "$basedir/dovelist"
rm "$basedir/filelist"
rm "$basedir/dovelist"
fi
echo "Checking dovecot installed packages"
apt-cache policy dovecot-* > aptinst
# get the line numbers where dovecot- exists
grep -n "dovecot-" aptinst | sed 's/\:/ /' | awk '{print$1}' > lines
a1=$(wc -l lines | awk '{print$1}')
for i in $(seq "$a1")
do
# read i line from lines file"
ln=$(sed -n ${i}p lines)
# add +1 to that line number (this will get Installed line)
ln=$((ln+1))
# On installed line bings up variable 2
rdinst=$(sed -n ${ln}p aptinst | awk '{print$2}' | sed 's/^.*://')
rjct="(none)"
echo "reading line $ln with output $rdinst"
# here checks if variable 2 is not equal to (none)
# (none) means package not installed
# in case some particular package is installed then a #version number will appear on variable2
if [[ "$rdinst" -ne "$rjct" ]]
then
if [[ ! -f "$basedir/installed" ]]
then
namepkg=$(sed -n ${i}p aptinst)
echo "Installed $namepkg with version $rdinst" > installed
else
namepkg=$(sed -n ${i}p aptinst)
echo "Installed $namepkg with version $rdinst" >> installed
fi
fi
done
exit 0
Eventually the problem is in the if statement , i changed the -ne with != and i did not get accurate output
The != is the correct operator to compare strings. You might use "set -x" or "set -xv" earlier in the script and watch what it tells you about the process.
Some random comments. Making a directory and subdirectory can be done in a single move:
if [[ ! -d "$basedir" ]]
then
mkdir "$basedir"
mkdir "$basedir/update"
else
rm -f "$basedir/update/*.*"
rm "$basedir/dovelist"
rm "$basedir/filelist"
rm "$basedir/dovelist"
fi
can be changed to
Code:
if [[ ! -d "$basedir" ]]
then
mkdir -p "$basedir/update"
else
rm -rf "$basedir/*
fi
leaving the $basedir there and everything within it deleted. remove the * if you want to delete that dir too.
this here
Code:
if [[ "$rdinst" -ne "$rjct" ]]
just checks the file names against each other, so they will never match if not named the same, you got a look inside of them.
example
Code:
#!/usr/bin/env bash
##check contents first line to see if match
f1=$HOME/test/ckfile1
f2=$HOME/test/ckfile2
if [[ $(cat $f1 | head -n1) == $(cat $f2 | head -n1) ]] ; then
echo "match"
else
echo "no match"
fi
MOD:
as @Turbocapitalist posted ahead of me, that awk he is doing is prob best to get what info out of the file that is needed to be checked against.
Why is the cat there? Wont that read the whole file then truncate, instead of just using head to read the first line?
Code:
head -n1 "$f1"
thanks, I never really used head to know how to input to it so I just defaulted to cat first then head it.
Code:
#!/usr/bin/env bash
##check contents first line to see if match
f1=$HOME/test/ckfile1
f2=$HOME/test/ckfile2
if [[ $(head -n1 $f1) == $(head -n1 $f2) ]] ; then
echo "match"
else
echo "no match"
fi
I am not comparing files , what i am doing is to see in "Installed" field , pick whats next "var2" , and if output is different than "(none)" then pick up the name of that installed package only to a file .
example :
when loop gets to dovecot-pigeonhole-dbg:
it reads the next line "Installed" , then grabs "2:2.3.9.2-1+debian10" and compare with "(none)" .
In case it is different then writes "dovecot-pigeonhole-dbg:" to a file .
I am pretty sure there is a simple way to do this , and i have faith that someone here already figured out to do it in a single line .
Quote:
dovecot-abi-2.2.abiv27:
Installed: (none)
Candidate: (none)
Version table:
dovecot-abi-2.2.abiv33:
Installed: (none)
Candidate: (none)
Version table:
dovecot-pigeonhole-dbg:
Installed: 2:2.3.9.2-1+debian10
Candidate: 2:2.3.9.2-1+debian10
Version table:
*** 2:2.3.9.2-1+debian10 100
100 /var/lib/dpkg/status
I am not comparing files , what i am doing is to see in "Installed" field , pick whats next "var2" , and if output is different than "(none)" then pick up the name of that installed package only to a file .
Ah - this is why it's a good idea to explain what you're trying to achieve before explaining what you're stuck on, because you're right - this can be done in one line:
packages.txt contains the quoted text in your post.
Uses -P for Perl regex to get lookahead support, with -z to match across lines, and -o to only output the matched text.
The "(?<=\n|\A)" is start of line/content - it would ideally just be "^" but that's not supported with the -z flag.
The "dovecot.*" searches for all dovecot prefixed packages - if you need specific ones, replace it with "(package1|package2)"
The next bit looks for "\nInstalled: " that isn't followed by "(none)\n" - using a lookahead to not include it in the output.
This version does include the colon in the output, but if you don't actually want that, move the : inside the lookahead (i.e. just before the \n )
Assumes the "Installed:" line always directly follows the package name, which seems a safe assumption? If not, (and depending on exact format possibilities), I might filter the content first to remove other lines.
But these outputs may change from system to system depending on witch packages a sys admin may have installed .
This is why i cant specify a specific package to grep .
And this is why i need to look into each package "Installed" field to see if have "(none)" or is different .
That looks like the same ten entries as your expected output.
You can even remove "dovecot" (leaving just the ".*" part) and it will continue to work even with package names not starting with dovecot (that might not be required, just pointing out the potential).
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.