0

I have this code where I want to check if a name attribute in JSON objects contains a particular word.

In the fetchLog function, I am using jq to query objects that contain a particular word. The function checkName in the jq code to check if the name attribute contains the keyword $1 which is an argument to the function fetchLog.

function fetchLog(){
   jq -r '.roots.bookmark_bar.children[]' | \
   jq '{name,url} | select((checkName .name $1) == true)' bookmark.json
}

function checkName()
{
   if [[ $1 == *"$2"* ]]; then
      echo true
   else
      echo false
   fi
}

bookmark.json contain:

{
  "name": "Networking",
  "url": "https://www.youtube.com/watch?v=AhOU2eOpmX0&list=PLIFyRwBY_4bRLmKfP1KnZA6rZbRHtxmXi&index=7"
}
{
  "name": "algorithm - How are ssl certificates verified? - Stack Overflow",
  "url": "https://stackoverflow.com/questions/188266/how-are-ssl-certificates-verified"
}
{
  "name": "(170) What is SSL & TLS ? What is HTTPS ? What is an SSL VPN? - Practical TLS - YouTube",
  "url": "https://www.youtube.com/watch?v=HMoFvRK4HUo&list=PLIFyRwBY_4bTwRX__Zn4-letrtpSj1mzY"
}

When I run fetchLog networking.

I keep getting an error:

+ jq '{name,url} | select((checkName .name $1) == true)'
jq: error: syntax error, unexpected '$' (Unix shell quoting issues?) at <top-level>, line 1:
{name,url} | select((checkName .name $1) == true)                                     
jq: 1 compile error

I expected the output of

fetchLog networking

to be

{
    "name": "Networking",
    "url": "https://www.youtube.com/watch?v=AhOU2eOpmX0&list=PLIFyRwBY_4bRLmKfP1KnZA6rZbRHtxmXi&index=7"
}

instead of the error:

+ jq '{name,url} | select((checkName .name $1) == true)'
jq: error: syntax error, unexpected '$' (Unix shell quoting issues?) at <top-level>, line 1:
{name,url} | select((checkName .name $1) == true)                                     
jq: 1 compile error
Tmak
  • 1
  • 1
  • You cannot just mix the constructs from different languages (here Bash and jq). But if you rewrite your custom function in jq (here, e.g. using `contains`), there are ways to get that jq function into your actual jq filter's body, where the function can be called from (e.g. prepeding code blocks, or using jq [Modules](https://jqlang.github.io/jq/manual/#Modules)). On a side note: Neither jq's `contains` nor `*"$2"*` in Bash is by itself case-insensitive. – pmf Jul 16 '23 at 20:02

1 Answers1

1

Is there a way I can pass my custom function to jq select function?

No, not if it's a bash function. See also @pmf's comments.

In the context of jq (and in many other contexts as well), it's usually better to think in terms of "passing in data" rather than "passing in functions". In the present case, the latter leads to a very simple solution.

If bookmark.json contains the stream of JSON as shown, then you could simply use the following invocation of jq to obtain the desired result:

< bookmark.json jq -r --arg keyword Networking '
  select(.name | index($keyword))
' 

As pointed out by @pmf, index is case-sensitive. If you want the check to be case-insensitive, then there are various possibilities, depending on your detailed requirements, e.g. with respect to robustness, Unicode case-folding rules, etc. One possibility to consider would be to use ascii_upcase, e.g.:

    ($keyword | ascii_upcase) as $k
    | select(.name | ascii_upcase | index($k))
peak
  • 105,803
  • 17
  • 152
  • 177