When does ruby parse int in yaml - ruby

I created this example yaml:
---
01:
01:
"01"
02:
"02"
03:
"03"
04:
"04"
05:
"05"
06:
"06"
07:
"07"
08:
"08"
09:
"09"
10:
"10"
11:
"11"
When I read this file like the following
require 'yaml'
yml = YAML.load_file(File.join('/home/user', 'test.yml'))
p yml
the output is
{1=>{1=>"01", 2=>"02", 3=>"03", 4=>"04", 5=>"05", 6=>"06", 7=>"07", "08"=>"08", "09"=>"09", 10=>"10", 11=>"11"}}
Now my question is:
Why are the keys 1 until 7 parsed as int while the keys 08 and 09 are not parsed as int by rubys yaml-parser but as string, i.e. "08" and "09" respectively?
I am using ruby 3.0.2

The keys 00 to 07 are parsed as octal digits because of the leading 0. Examples:
00
#=> 0
05
#=> 5
07
#=> 7
08 and 09 are simply invalid octal digits, and therefore the parser returns those keys in their string representation. Example:
08
#=> Invalid octal digit (SyntaxError)
09
#=> Invalid octal digit (SyntaxError)

Related

Inconsistent results when comparing numeric variables in bash if statement [duplicate]

This question already has answers here:
Value too great for base (error token is "09")
(7 answers)
Value too great for base (error token is "08") [duplicate]
(1 answer)
Closed last month.
I have a bash script that performs commands on files based on dates contained in the file names. I'd like certain commands to run only for months greater than the current month, so I attempted to add an if statement that compares the variables $day (containing the numeric value of the month, taken from the for loop's parameter) and $thismonth (populated using date).
For most values of month the script works as expected, but when it loops through 08 and 09 it produces errors, e.g. value too great for base (error token is "08"). Is there some difference between the values 08 and 09 and all the others...? Or what other mistake have I made?
Minimal example test.sh:
Note: I'm a scripting novice so please feel free to correct any mistakes or inefficiencies even if not causing this particular issue. Also, parameters of the for loop came from an answer to How to loop through dates using Bash?.
for d in 02{01..28} {04,06,09,11}{01..30} {01,03,05,07,08,10,12}{01..31}
do
day=${d: -2}
month=${d::2}
thismonth=$(date +%m)
if [[ "$month" -gt "$thismonth" ]]; then
echo day is $day
echo the month is $month
echo this month is $thismonth
echo Greater than this month
echo "" # to make output more easily readable
else
echo day is $day
echo the month is $month
echo this month is $thismonth
echo NOT greater than this month
echo "" # to make output more easily readable
fi
done
Expected results:
# for values of `month` between `02` and `12`
day is <value of $day>
the month is <value between 02 and 12>
this month is 01
Greater than this month
# when `month` is `01`:
day is <value of $day>
the month is 01
this month is 01
NOT greater than this month
Actual results are as expected for all values of month except 08 and 09. Excerpted output (repetitive lines removed):
day is 01
the month is 02
this month is 01
Greater than this month
[ . . . ]
day is 30
the month is 06
this month is 01
Greater than this month
./test.sh: line 7: [[: 09: value too great for base (error token is "09")
day is 01
the month is 09
this month is 01
NOT greater than this month
[ . . . ]
./test.sh: line 7: [[: 09: value too great for base (error token is "09")
day is 30
the month is 09
this month is 01
NOT greater than this month
day is 01
the month is 11
this month is 01
Greater than this month
[ . . . ]
day is 30
the month is 11
this month is 01
Greater than this month
day is 01
the month is 01
this month is 01
NOT greater than this month
[ . . . ]
day is 31
the month is 01
this month is 01
NOT greater than this month
day is 01
the month is 03
this month is 01
Greater than this month
[ . . . ]
day is 31
the month is 07
this month is 01
Greater than this month
./test.sh: line 7: [[: 08: value too great for base (error token is "08")
day is 01
the month is 08
this month is 01
NOT greater than this month
[ . . . ]
./test.sh: line 7: [[: 08: value too great for base (error token is "08")
day is 31
the month is 08
this month is 01
NOT greater than this month
day is 01
the month is 10
this month is 01
Greater than this month
[ . . . ]
day is 31
the month is 12
this month is 01
Greater than this month
This seemed especially surprising since these months are in different groups of the for loop parameter (i.e. apparently unrelated to the fact that one loops through days 01 to 30 vs 01 to 31 so also not somehow related to number of days in thismonth or something like that).
The full script (which checks for files named with dates formatted yyyymmdd and removes certain those with certain dates) worked fine in the latter part of last year when I wanted to see results for all dates, but gave the above odd results when I added the if statement in the minimal example in order to prevent output results for months greater than the current one (since no files yet exist for dates later than today).
bash --version is GNU bash, version 5.1.4(1)-release on Debian GNU/Linux 11 (bullseye) (actually running Proxmox kernel where uname -srv is Linux 5.15.39-4-pve #1 SMP PVE 5.15.39-4 (Mon, 08 Aug 2022 15:11:15 +0200) in case that's somehow relevant).

print array range once string is found KSH93 Version M

My need is to print a range of array elements, minus 20 and plus 20 elements from the point "string" is found using KSH93.
I have tried many iterations of code and read many links for example,
How do I iterate over a range of numbers defined by variables in Bash?
/usr/bin/ksh93 -c 'mdm=(`/usr/sbin/mdmprpt 2>/dev/null`);
for index in "${!mdm[#]}"; do
if [[ ${mdm[$index]} =~ Fault.? ]]; then
i=${mdm[$index]};
for x in {1..$i}; do
echo $x
done
fi
done
actual result is
{1..(Faulting}
when it should print 20 lines before and or after of index 52. Ideally both.
__Raw Data__from_sample_code
mdm[32] is 6400000000000000
mdm[33] is 0000000000000000
mdm[34] is 0000000000000000
mdm[35] is 0000000000000000
mdm[36] is 00000000
mdm[37] is Symptom
mdm[38] is Information:
mdm[39] is Crash
mdm[40] is Location:
mdm[41] is [000000000010D614]
mdm[42] is IPRA.$ha_critic+114
mdm[43] is Component:
mdm[44] is COMP
mdm[45] is Exception
mdm[46] is Type:
mdm[47] is 131
mdm[48] is Data
mdm[49] is From
mdm[50] is CPU
mdm[51] is #8
mdm[52] is (Faulting
mdm[53] is CPU)
mdm[54] is backup_files
mdm[55] is cfgbackups
mdm[56] is config
mdm[57] is install.log
mdm[58] is ioscli.log
mdm[59] is pager.trace
mdm[60] is rules
mdm[61] is smit.log
mdm[62] is smit.script
mdm[63] is smit.transaction
mdm[64] is snap.pax.Z
mdm[65] is MST
mdm[66] is State:
mdm[67] is R0:
mdm[68] is 0000000000050FB4
mdm[69] is R1:
mdm[70] is F00000002FF471D0
mdm[71] is R2:
mdm[72] is 00000000038B6110
When you find the matching string you also have its (numerical) index (${index}), so just +/-20 to ${index} to get the desired range.
We'll also need some additional logic to make sure our desired range of indexes falls within the range of available indexes. Keep in mind that for an array with 'n' records the available index range will be '0 to (n-1)'.
for index in "${!mdm[#]}"
do
if [[ ${mdm[$index]} =~ Fault.? ]]
then
start=$((index-20))
end=$((index+20))
# if 'start' is less than 0 then reset it to 0
[ ${start} -lt 0 ] && start=0
for x in $( seq ${start} ${end} )
do
# break if we run out of array elements
[ "${mdm[${x}]:-undefined}" = 'undefined' ] && break
# display our numeric index and contents of associated array item
echo "${x} : ${mdm[${x}]}"
done
break
fi
done
I created a data file with 32 initial lines of 'XXXXXX', the 41 lines of sample data from the question, and an additional dozen lines of 'XXXXXX' at the end of the file; I then ran the above code snippet against the file and generated:
32 : 6400000000000000
33 : 0000000000000000
34 : 0000000000000000
35 : 0000000000000000
36 : 00000000
37 : Symptom
38 : Information:
39 : Crash
40 : Location:
41 : [000000000010D614]
42 : IPRA.$ha_critic+114
43 : Component:
44 : COMP
45 : Exception
46 : Type:
47 : 131
48 : Data
49 : From
50 : CPU
51 : #8
52 : (Faulting
53 : CPU)
54 : backup_files
55 : cfgbackups
56 : config
57 : install.log
58 : ioscli.log
59 : pager.trace
60 : rules
61 : smit.log
62 : smit.script
63 : smit.transaction
64 : snap.pax.Z
65 : MST
66 : State:
67 : R0:
68 : 0000000000050FB4
69 : R1:
70 : F00000002FF471D0
71 : R2:
72 : 00000000038B6110
Well I could just use a bunch of prints, which does do what I want, but Id think there would be a range operator I have yet to get to work.
/usr/bin/ksh93 -c 'mdm=(`/usr/sbin/mdmprpt 2>/dev/null`);
for index in "${!mdm[#]}"; do
if [[ ${mdm[$index]} =~ Fault.? ]]; then
print ${mdm[$index-20]}
print ${mdm[$index-19]}
print ${mdm[$index-18]}
print ${mdm[$index-17]}
print ${mdm[$index-16]}
print ${mdm[$index-15]}
print ${mdm[$index-14]}
print ${mdm[$index-13]}
print ${mdm[$index-12]}
print ${mdm[$index-11]}
print ${mdm[$index-10]}
print ${mdm[$index-9]}
print ${mdm[$index-8]}
print ${mdm[$index-7]}
print ${mdm[$index-6]}
print ${mdm[$index-5]}
print ${mdm[$index-4]}
print ${mdm[$index-3]}
print ${mdm[$index-2]}
print ${mdm[$index-1]}
print ${mdm[$index]}
fi
done'
6400000000000000
0000000000000000
0000000000000000
0000000000000000
00000000
Symptom
Information:
Crash
Location:
[000000000010D614]
IPRA.$ha_critic+114
Component:
COMP
Exception
Type:
131
Data
From
CPU
8
(Faulting

How to get the data from log file with different months in unix?

I want to get the data between two times in a log file of different months and date.Suppose if my startime is not present in the logfile, then I want to extract the data from the nearest next time in the logfile. And also it has to end before the endtime, if the entered endtime is not present in the log file.
My log file data,
Apr 10 16 02:07:20 Data 1
Apr 11 16 02:07:20 Data 1
May 10 16 04:11:09 Data 2
May 12 16 04:11:09 Data 2
Jun 11 16 06:22:35 Data 3
Jun 12 16 06:22:35 Data 3
The solution I am using is,
awk -v start="$StartTime" -v stop="$EndTime" 'start <= $StartTime && $EndTime <= stop' $file
where, I am storing my starttime in $StartTime and endtime in $EndTimeBut Iam not getting the exact output. Please help.
Something like this maybe:
$ BashVarStart="16 05 10 00 00 00" # the same format that awk function will reformat to
$ BashVarStop="16 06 11 00 00 00"
$ awk -v start="$BashVarStart" -v stop="$BashVarStop" -F"[ :]" -v OFS=\ '
function reformatdate(m,d,y,h,mm,s) { # basically throw year to the beginning
monstr="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"; # numerize the months
split(monstr,monarr," "); # split monstr to an array to enumerate the months
# monarr[1]="Jan", monarr[2]="Feb" etc
for(i in monarr) { # iterate over all month numbers in monarr index
if(monarr[i]==m) # when month number matches
m=sprintf("%02d",i) # zeropad if month number below 10: 9 -> 09
};
return y" "m" "d" "h" "mm" "s # return in different order
}
start < reformatdate($1,$2,$3,$4,$5,$6) && stop > reformatdate($1,$2,$3,$4,$5,$6)
' test.in
May 10 16 04:11:09 Data 2
May 12 16 04:11:09 Data 2

Sort a dict by its value pairs

I have a dict which looks like this:
Unsorted:
12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8 {89 302} 55 {44 301}
I would like to sort it like this:
55 {44 301} 27 {301 302} 8 {89 302} 29 {89 12} 12 {12 489} 26 {489 329}
As you can see, most of the time the second key value of the preceding entry is identical to the first key entry of the following entry. ( 12 and 489 in the last two entries)
This although is no requirement. The 302 of the second and third entry also fullfills the requirement of a "chain" as it exists in both the second and the third entry.
The only thing I want to do is sorting these entries in such a way, that the values in braces form a uninterupted chain.
It does not matter if the result looks like in the example or if it is mirrored.
From TCL 8.6 on I could do something similar to Sort Tcl dict by value using stride. But I'm stuck with this (Tcl8.5.9) version. What is the easiest way to this?
I don't know if this is the easiest way:
set x [dict create 12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8 {89 302} 55 {44 301}]
# transform the dict into a list of lists
dict for {k v} $x {lappend unsorted [list $k $v]}
lappend sorted [lindex $unsorted 0]
set unsorted [lrange $unsorted 1 end]
# keep going until there's nothing more to add to the sorted list
while {[llength $unsorted] != 0} {
set changed false
for {set idx 0} {$idx < [llength $unsorted]} {incr idx} {
set elem [lindex $unsorted $idx]
lassign [lindex $elem end] a b
set head [lindex $sorted 0 end]
set tail [lindex $sorted end end]
if {$a in $head || $b in $head} {
set sorted [linsert $sorted 0 $elem]
set changed true
} elseif {$a in $tail || $b in $tail} {
lappend sorted $elem
set changed true
}
if {$changed} {
set unsorted [lreplace $unsorted $idx $idx]
break
}
}
# avoid infinite loop if the unsorted list is not empty, but
# contains nothing to add to the sorted list
if {! $changed} break
}
foreach elem $sorted {dict set y {*}$elem}
puts "Unsorted: $x"
puts "Sorted: $y"
Unsorted: 12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8 {89 302} 55 {44 301}
Sorted: 55 {44 301} 27 {301 302} 8 {89 302} 29 {89 12} 12 {12 489} 26 {489 329}

Ruby / Date Parse Hour

How do I time parse these strings below:
01
02
03
So that I can use strftime('%I %p') to make it into:
01 AM
02 AM
03 AM
require 'date'
DateTime.strptime('01', '%H').strftime('%0l %p')
=> "01 AM"
That said, if the string is already '01' why not just stick an AM or PM on it? Can just use to_i to determine if it's before/after noon.

Resources