I have a array named $applist. The values are used to generate cron entries like this
$minute = 0
$applist.each |$application| {
$minute = $minute + 2
# notify{"Setting clear_logs for ${application}":}
# generate clear log entries
cron {"clear-logs_${application}":
command => "mk-job clear-logs_${application} /root/scripts/clear_logs.py -l 60 -d ${application}/logs -v -n >/dev/null 2>&1",
user => root,
hour => "3",
minute => "${minute}",
}
}
Minute is not increased by 2 in my iteration steps. I am pretty sure it is related to lamdas but I have no Idea how to solve this dilemma
It's a good question and the above is the correct solution.
I would add that the problem here is that variables in Puppet cannot be reassigned: ref.
Ordinarily, if you had code like the following -
$c = 0
$c = $c + 1
You would receive an Evaluation Error:
Error: Evaluation Error: Cannot reassign variable '$c' (file: /tmp/foo.pp, line: 2, column: 4) on node alexs-macbook-pro.local
It is often noted that Puppet's variables therefore aren't "variable" ; they are immutable.
Even more confusingly, this behaviour changes inside an iterator block. Consider this code more similar to the sample from the question:
$c = 0
[1, 2, 3].each |$x| {
$c = $c + 1
notice($c)
}
Now the code compiles fine, but Puppet still can't reassign the variable $c:
$ puppet apply /tmp/foo.pp
Notice: Scope(Class[main]): 1
Notice: Scope(Class[main]): 1
Notice: Scope(Class[main]): 1
The best thing to do here is as is shown in the OP's answer to their question, and use each with an index (analogous to Ruby's each_with_index but with a slightly different grammar): ref.
Consider:
$c = 0
[1, 2, 3].each |$i, $x| {
notice("Index is $i, x is $x")
}
Now we get:
Notice: Scope(Class[main]): Index is 0, x is 1
Notice: Scope(Class[main]): Index is 1, x is 2
Notice: Scope(Class[main]): Index is 2, x is 3
I solved it using $index like this
$minute = 0
$applist.each |$index, $application| {
$cron_minute = $minute + $index * 10
# notify{"Setting clear_logs for ${application}":}
# generate clear log entries
cron {"clear-logs_${application}":
command => "mk-job clear-logs_${application} /root/scripts/clear_logs.py -l 60 -d ${application}/logs -v -n >/dev/null 2>&1",
user => root,
hour => "3",
minute => "${cron_minute}",
}
}
Related
I'm trying to calculate time difference stored inside of two variables inside of a shell script, I'm observing the following pattern:
hhmm -> 0950
so:
time1=1333
time2=0950
Now I need to calculate the difference in time between time1 and time2, as for now I have tried:
deltaTime=$(($time1-$time2))
but I'm facing the following error message
1333-0950: value too great for base (error token is "0950")
I'm expecting as a result: $deltaTime=0343
Unfortunately, I am strictly bound to use this time pattern. I have already researched for a solution online, some of them propose to use date -d... but I couldn't get it to work :(
Your approach has two issues.
First issue: bash recognizes numbers with leading zeroes as octal. You can force base10 by adding 10# prefix.
Second issue: it is incorrect to consider strings in hhmm format as numbers and substract them. e.g. 1333-950=383 but difference between 09:50 and 13:33 is 3 hours and 43 minutes. You should convert string values to common units, e.g. to minutes, substract them and convert back to hhmm format.
time1=1333
time2=0950
str2min()
{
printf "%u" $((10#${1%??} * 60 + 10#${1#??}))
}
min2str()
{
printf "%02u%02u" $(($1 / 60)) $(($1 % 60))
}
time1m=$(str2min $time1)
time2m=$(str2min $time2)
timediff=$(($time1m - $time2m))
deltaTime=$(min2str $timediff)
You could use this implementation maybe?
#!/usr/bin/env bash
diff_hhmm() {
local -r from=$1
local -i from_hh=10#${from:0:2} # skip 0 chars, read 2 chars (`${from:0:2}`) using base 10 (`10#`)
local -ri from_mm=10#${from:2:2} # skip 2 chars, read 2 chars (`${from:0:2}`) using base 10 (`10#`)
local -r upto=$2
local -ri upto_hh=10#${upto:0:2}
local -ri upto_mm=10#${upto:2:2}
local -i diff_hh
local -i diff_mm
# Compute difference in minutes
(( diff_mm = from_mm - upto_mm ))
# If it's negative, we've "breached" into the previous hour, so adjust
# the `diff_mm` value to be modulo 60 and compensate the `from_hh` var
# to reflect that we've already subtracted some of the minutes there.
if (( diff_mm < 0 )); then
(( diff_mm += 60 ))
(( from_hh -= 1 ))
fi
# Compute difference in hours
(( diff_hh = from_hh - upto_hh ))
# Ensure the result is modulo 24, the number of hours in a day.
if (( diff_hh < 0 )); then
(( diff_hh += 24 ))
fi
# Print the values with 0-padding if necessary.
printf '%02d%02d\n' "$diff_hh" "$diff_mm"
}
$ diff_hhmm 1333 0950
0343
$ diff_hhmm 0733 0950
2143
$ diff_hhmm 0733 0930
2203
Or an even shorter implementation using a big arithmetic compound command ((( ... )) ) and inlining some variables:
diff_hhmm_terse() {
local -i diff_hh diff_mm
((
diff_mm = 10#${1:2:2} - 10#${2:2:2},
diff_hh = 10#${1:0:2} - 10#${2:0:2},
diff_hh -= diff_mm < 0 ? 1 : 0,
diff_mm += diff_mm < 0 ? 60 : 0,
diff_hh += diff_hh < 0 ? 24 : 0
))
printf '%02d%02d\n' "$diff_hh" "$diff_mm"
}
Do you have the possibility to drop the leading zero?
As you can see from my prompt:
Prompt> echo $((1333-0950))
-bash: 1333-0950: value too great for base (error token is "0950")
Prompt> echo $((1333-950))
383
Other proposal:
date '+%s'
Let me give you some examples:
date '+%s'
1662357975
... (after some time)
date '+%s'
1662458180
=>
echo $((1662458180-1662357975))
100205 (amount of seconds)
=>
echo $(((1662458180-1662357975)/3600))
27 (amount of hours)
This bash one-liner may be used if time difference is not negative (that is, time1 >= time2):
printf '%04d\n' $(( 10#$time1 - 10#$time2 - (10#${time1: -2} < 10#${time2: -2} ? 40 : 0) ))
I am trying to make a script that outputs a status bar for my window manager. It outputs the normal stuff like the time, date, weather, etc.
One of the strings it outputs is the number of updates for the system (Arch Linux). As the "API" where I am pulling the update number from has a max number of requests per day I had to add a delay to the updates() function (that outputs the number of updates) so that that maximum number of requests is not exceeded.
Adding this delay makes the problem start.
Somehow the updates_aur variable is not being stored in memory and cannot be accessed until the delay I implemented is removed. (MORE EXPLANATION IN CODE BELOW)
I would like for a delay to be implemented that makes the updates not being checked every iteration but one in 60.
I tried exporting the "updates_aur" and the "updates_arch" to environment variables so that they would be stored in memory but as the script creates a subshell they are not accessible for them to be updated/retrieved.
updates() {
if [ "$internet" = true ]; then
if ! updates_arch=$(checkupdates 2> /dev/null | wc -l ); then
updates_arch=0
fi
if (( $counter % 60 == 0 )); then #this is done to add a delay and not saturate aur requests
if ! updates_aur=$(yay -Qum --devel 2> /dev/null | wc -l); then
updates_aur=0
fi
else
:
fi
updates=$(("$updates_arch" + "$updates_aur"))
if [ "$updates" -gt 0 ]; then
echo " Updates: $updates"
else
echo " Updates: 0"
fi
echo $delim
else
:
fi
}
This is then called in a while loop (the while loop also increments the counter by 1)
Full code: https://github.com/Baitinq/dwm/blob/master/scripts/dwm-status
I expected the variable of aur_updates to be updated and stored whenever the counter % 60 == 0, but the actual result is that the variable can only be accessed when the counter % 60 == 0, as if it wasn't being stored in memory and updated, but created with every while loop iteration in which the counter % 60 == 0.
Since you're running your functions in a subshell, for example (from the status function):
echo $(updates)
Their variables' (updates_aur) values are lost when the subshell exits. There's no reason to echo a function that contains an echo within it. Just call your function directly:
updates
This occurs in several places with other functions. It's also not necessary there.
I am running a script that bumps a parameter value in a file:
Before the script executes:
$cat file
revision 1.2 date: 2018/11/15 09:28:12; author: root; state: Exp;
lines: +1 -1
After running the script:
$cat file
revision 1.3 date: 2018/11/15 09:28:12; author: root; state: Exp;
lines: +1 -1 revision 1.2 date: 2018/11/15 09:28:12; author: root;
state: Exp; lines: +1 -1
I need a script that could checks if the version is updated/bumped as one version greater than the previous version, if yes it should echo the message as 'Script ran successfully'.
$grep -iw 'revision' file | head -1 | cut -d' ' -f2
1.2
$sh <script>
$grep -iw 'revision' file | head -1 | cut -d' ' -f2
1.3
$echo -e "Script ran successfully!!! \n"
Here's a function bumped that will compare to version strings and determine if they are in succession. I made a couple of assumptions in the comparison. The number of "decimal points" has to be the same. I also have left the door wide open for big errors , see my last test case. Consider this quick and dirty. It would probably be better to write logic to compare each decimal value and make sure that the last decimal place was one more than the previous. A more correct version would be able to compare a.b.c with d.e.f by first comparing a == d , then b == c , and then f == c + 1. However, depending on what you are trying to do, quick and dirty may be the easiest to maintain.
Without any additional discussion, here is the quick and dirty version:
function bumped() {
prev=$1
next=$2
PREV=$( sed 's/[^0-9]//g' <<<"$prev" )
NEXT=$( sed 's/[^0-9]//g' <<<"$next" )
[ $(( NEXT - PREV )) -eq 1 ]
}
function testcases() {
cat <<EOF
1.2 1.3 0
1.3 1.2 1
1.2.1 1.2.2 0
1.3 1.3.1 1
EOF
}
testcases | while
read prev next expected extra
do
bumped $prev $next
observed=$?
result="Success"
[ $observed -ne $expected ] && result="Failed"
echo "$result: bumped( $prev , $next ) = $observed ( expected: $expected )"
done
The above program yields these results:
Success: bumped( 1.2 , 1.3 ) = 0 ( expected: 0 )
Success: bumped( 1.3 , 1.2 ) = 1 ( expected: 1 )
Success: bumped( 1.2.1 , 1.2.2 ) = 0 ( expected: 0 )
Success: bumped( 1.3 , 1.3.1 ) = 1 ( expected: 1 )
Failed: bumped( 1.3.1.1 , 13.1.2 ) = 0 ( expected: 1 )
So clearly this is not an optimal solution, but it may get you where you need to go. If you are looking for something that is correct all the time, consider the logic discussed above.
I'm trying to batch modify some images using a bash script, and to print out the progress. It looks to me like bash is interpreting the increment to counter as a command and is giving the following error:
augment_data.sh: line 20: 0: command not found
Here is the code:
for file in *.jpg
do
convert $file -rotate 90 rotated_"$file"
((counter++))
if $((counter % 10 == 0)); then
echo "Rotated $counter files out of $num_files"
fi
done
with line 20 being the one with the counter increment operation.
How can I fix this so that I don't get the error message?
In an arithmetic substitution, the result of an arithmetic operation is substituted in the position of the operation itself.
In this case, $(( 1 == 0 )) has an arithmetic result of 0, and $(( 1 == 1 )) has a result of 1.
Thus, if you use $(( ... )), then this 0 or 1 is substituted in that position, and so gets run as a command. Since you don't have commands named 0 or 1 (probably), either of these will result in a command not found error.
If you use (( ... )), then the arithmetic result directly sets return value, but no expansion takes place.
function dec_to_bin {
if [ $# != 2 ]
then
return -1
else
declare -a ARRAY[30]
declare -i INDEX=0
declare -i TEMP=$2
declare -i TEMP2=0
while [ $TEMP -gt 0 ]
do
TEMP2="$TEMP%2"
#printf "%d" "$TEMP2"
ARRAY[$INDEX]=$TEMP2
TEMP=$TEMP/2
INDEX=$[ $INDEX + 1 ] #note
done
for (( COUNT=INDEX; COUNT>-1; COUNT--)){
printf "%d" "${ARRAY[$COUNT]}" <<LINE 27
#echo -n ${ARRAY[$COUNT]} <<LINE 28
}
fi
}
why is this code giving this error
q5.sh: line 27: ARRAY[$COUNT]: unbound variable
same error comes with line 28 if uncommented
One more question, I am confused with the difference b/w '' and "" used in bash scripting any link to some nice article will be helpfull.
It works fine for me except that you can't do return -1. The usual error value is 1.
The error message is because you have set -u and you're starting your for loop at INDEX instead of INDEX-1 (${ARRAY[INDEX]} will always be empty because of the way your while loop is written). Since you're using %d in your printf statement, empty variables will print as "0" (if set -u is not in effect).
Also, it's meaningless to declare an array with a size. Arrays in Bash are completely dynamic.
I would code the for loop with a test for 0 (because the -1 looks confusing since it can't be the index of an numerically indexed array):
for (( COUNT=INDEX - 1; COUNT>=0; COUNT--))
This form is deprecated:
INDEX=$[ $INDEX + 1 ]
Use this instead:
INDEX=$(( $INDEX + 1 ))
or this:
((INDEX++))
I also recommend using lower case or mixed case variables as a habit to reduce the chance of variable name collision with shell variables.
You're not using $1 for anything.