Why is `jq` trying to `add` to an object in a variable assignment? - sh

Given the following jq pipeline of expressions:
echo '{"foo": 1}' | jq '.foo + 2 as $bar | {$bar}'
I would expect the output:
{
"bar": 3
}
What I get is:
jq: error (at <stdin>:1): number (1) and object ({"bar":2}) cannot be added
What is this object and why is jq trying to add to it?
I can resolve this issue with parentheses but I'm still unclear as to what was happening in the original statement:
echo '{"foo": 1}' | jq '(.foo + 2) as $bar | {$bar}'
{
"bar": 3
}

Your first filter was executed as if it had been parenthesized like this
echo '{"foo": 1}' | jq '.foo + (2 as $bar | {$bar})'
Thus, jq tried to add a number (here 1) to an object (here {"bar":2}).
This is because the syntax for a variable binding, as noted in the manual's corresponding section, takes on the form ... as $identifier | .... It "includes" the pipe and the following expression. This is reflected by the fact that a binding without the following pipe and expression cannot stand alone.

Related

Adding multiple lines to yaml file based on key

I have sample.yaml file that looks like the following:
a:
b:
- "x"
- "y"
- "z"
and I have another file called toadd.yaml that contains the following
- "first to add"
- "second to add"
I want to modify sample.yaml file so that it looks like:
a:
b:
- "x
- "y"
- "z"
- "first to add"
- "second to add"
Also, I dont want redundant naming! so if there is "x" already in toadd.yaml than I dont want it to be added two times in sample.yaml/a.b
Please note that I have tried the following:
while read line; do
yq '.a.b += ['$line']' sample.yaml
done <toadd.yaml
and I fell on:
Error: Bad expression, could not find matching `]`
If the files are relatively smaller, you could just directly load the second file on to the first. See Merging two files together
yq '.a.b += load("toadd.yaml")' sample.yaml
Tested on mikefarah/yq version 4.25.1
To solve the redundancy requirement, do a unique operation before forming the array again.
yq 'load("toadd.yaml") as $data | .a.b |= ( . + $data | unique )' sample.yaml
which can be further simplified to just
yq '.a.b |= ( . + load("toadd.yaml") | unique )' sample.yaml

Understanding ibase and obase used

I'm trying to solve the following exercise:
Write a command line that takes numbers from variables FT_NBR1, in ’\"?! base, and FT_NBR2, in mrdoc base, and displays the sum of both in gtaio luSnemf base.
I know the solution is:
echo $FT_NBR1 + $FT_NBR2 | sed 's/\\/1/g' | sed 's/?/3/g' | sed 's/!/4/g' | sed "s/\'/0/g" | sed "s/\"/2/g" | tr "mrdoc" "01234" | xargs echo "ibase=5; obase=23;" | bc | tr "0123456789ABC" "gtaio luSnemf"
I don't understand why ibase=5 and obase=23.
I read about ibase and obase, and I understand this is a base conversion, from base 5 to base 23. Anyone can explain me why 5 and 23. Thank you
The exercise description is a bit weird. A better one would be
Write a command line that takes numbers from variables FT_NBR1, with numbers represented by the letters "’\"?!", and FT_NBR2, represented by "mrdoc", and displays the sum of both with numbers represented by "gtaio luSnemf".
A shorter answer would be
echo $FT_NBR1 + $FT_NBR2 | tr "\'\\\\\"\?" "01234" | tr "mrdoc" "01234" | xargs echo "ibase=5; obase=23;" | bc | tr "0123456789ABC" "gtaio luSnemf"
Let's take it from the beginning:
echo $FT_NBR1 + $FT_NBR2 creates the expression using the input strings
tr "\'\\\\\"\?" "01234" translates the first input alphabet into numbers
tr "mrdoc" "01234" translates the second input alphabet into numbers
xargs echo "ibase=5; obase=23;" prepends number base information; the input base is 5 and the output base is 13, but obase must be expressed in the base of ibase and 13 in base 5 is 23.
bc does the actual calculation
tr "0123456789ABC" "gtaio luSnemf" does the translation into the output alphabet.

How to escape double backslashes so I can get "\\" in man page?

For example, my foo.adoc file looks like this:
= foo(1)
== NAME
foo - hello world
== SYNOPSIS
foo ...
== DESCRIPTION
\\ | \\\ | \\\\ | {backslash}{backslash}
But after asciidoctor -b manpage foo.adoc and man ./foo.1 would produce:
FOO(1) FOO(1)
NAME
foo - hello world
SYNOPSIS
foo ...
DESCRIPTION
\ | \\(rs | \\(rs | \
2019-07-03 FOO(1)
So how should I escaple to get double backslashes (\\) in man page?
It's actually a bug in Asciidoctor:
The regular expression that is used to preserve literal backslashes is malfunctioning. The backslash in the content is somehow getting mixed up with the backslash in the replacement. And we're also missing a test.
-- #mojavelinux
https://github.com/asciidoctor/asciidoctor/issues/3456
It should be fixed in the next release (2.0.11) of Asciidoctor.

Add square bracket only if one set of values [duplicate]

This question already has answers here:
ConvertTo-JSON an array with a single item
(7 answers)
Closed 4 years ago.
I'm using this scrip for Azure monitoring with Zabbix:https://b-blog.info/en/monitoring-azure-resources-with-zabbix.html
If only one SQL database in output:
{"data":{
"{#SERVERNAME}": "mojsql",
"{#ID}": "/subscriptions/11111-222222/resourceGroups/rg/providers/Microsoft.Sql/servers/mojsql/databases/mojabaza",
"{#DATABASENAME}": "mojabaza",
"{#RGNAME}": "rg"
}
}
If more than one database then output is:
{"data":[
{
"{#DATABASENAME}": "mojabaza",
"{#SERVERNAME}": "mojsql",
"{#RGNAME}": "rg",
"{#ID}": "/subscriptions1111-22222/resourceGroups/rg/providers/Microsoft.Sql/servers/mojsql/databases/mojabaza"
},
{
"{#DATABASENAME}": "mojabaza1",
"{#SERVERNAME}": "mojsql",
"{#RGNAME}": "rg",
"{#ID}": "/subscriptions/11111-22222/resourceGroups/rg/providers/Microsoft.Sql/servers/mojsql/databases/mojabaza1"
}
]
}
Note square brackets are added automatically.
The issue is if only one database in resource group then i must add square brackets in order to see database in zabbix
'{"data":' + '[' + $($result | ConvertTo-Json) + ']' + "`n}";
If more than one database then double square brackets are added and Zabbix shows error.
Is it possible to write a condition if one output then add square brackets something like
if $($results)=1 then
'{"data":' + '[' + $($result | ConvertTo-Json) + ']' + "`n}";
else
'{"data":' + $($result | ConvertTo-Json) + "`n}";
Your use case is exactly what the PowerShell's array subexpression operator, #(), was designed for:
'{"data":' + (ConvertTo-Json #($result)) + "`n}"
Wrapping a command in #(...) guarantees that its output is an array.
In other words:
If the output already is an array (collection), it is, loosely speaking, left alone (technically, a copy of the output array is typically created).
If it isn't, it is wrapped in a array, as the that array's only element.
Additionally, in order for ConvertTo-Json to see the array as such, you mustn't use the pipeline and instead pass it as an argument:
Because the pipeline unwraps (unrolls) arguments implicitly, the following two commands are identical:
$result | ...
#($result) | .... # !! identical

Avoiding nested objects using ModelBuilderSemantics in Grako

If you take a look at the grammar below, you can see a primary rule, expression, which gets parsed into more specific expression types.
expression::Expression
=
or_ex:and_expr {'||' or_ex:and_expr}+
| andex:and_expr
;
and_expr::AndExpression
=
and_ex:sub_expr {'&&' and_ex:sub_expr}+
| subex:sub_expr
;
sub_expr::SubExpression
=
{'!!'}* '!(' not_ex:expression ')'
| {'!!'}* '(' sub_ex:expression ')'
| compex:comp_expr
;
comp_expr::CompareExpression
=
comp:identifier operator:('>=' | '<=' | '==' | '!=' | '>' | '<') comp:identifier
;
identifier::str
=
?/[a-zA-Z][A-Za-z0-9_]*/?
;
The parsing of the test_input, below, works as expected, but I would prefer to label the and_expr element in the expression rule with an '#' instead of 'andex'. My hope was that the parsed output would result in only a CompareExpression object which is inside a not_ex element in an Expression object.
!(a == b)
It seems that when using the '#' label on the and_expr element, there are no attributes shown in the Expression object! Is this a bug or intentional? Must I label all elements with names and not use the '#' label when using ModelBuilderSemantics?
Another issue I've been facing is that if a later rule, such as comp_expr, did not have an associated class name, its elements would appear in a dictionary when printed, but the dot notation accessor would fail with an AttributeError, i.e. "AttributeError: 'dict' object has no attribute 'comp'". Is there any way to use the dot notation accessor even when rules do not have class names associated with them?
Some of the criteria I use:
Not every rule must have an associated Node class.
Rules with a closure {} as main expression are good for returning a list.
Rules with a a choice | as main expression are best returning whatever the successful option returns, even if this often requires factoring the option into its own rule.
Precedence is important.
Ect.
The idea is that generated parse model should be easy to use, specially with walkers, with a minimum of if-else or isinstance().
This is how I would do your example:
start
=
expression $
;
expression
=
| or_expre
| and_expre
| sub_expre
;
or_expre::OrExpression
=
operands:'||'.{and_expre}+
;
and_expr::AndExpression
=
operands:'&&'.{sub_expre}+
;
sub_expr
=
| not_expr
| comp_expre
| atomic
;
not_expre::NotExpression
=
'!!' ~ sub_expr
;
comp_expr::CompareExpression
=
lef:atomic operator:('>=' | '<=' | '==' | '!=' | '>' | '<') ~ right:atomic
;
atomic
=
| group_expre
| identifier
;
group_expr::GroupExpression
=
'(' ~ expre:expression ')'
;
identifier::str
=
/[a-zA-Z][A-Za-z0-9_]*/
;