0

I have a bash script that user enter name of a database and then my script needs to loop through this database config file. my JSON looks like this:

{
    "_id":1,
    "db_name":"postgres",
    "username":"postgres_user",
    "password":"postgres_pass",
    "daily" : {
               "days_to_backup" : [1,2],
               "delete_after" : 14,
               "compressed" : true,
           "path" : "localhost"
         },
    "monthly" : {
               "days_to_backup" : [2,5,30],
               "delete_after" : 7,
               "compressed" : false,
           "path" :" localhost"
         },
    "yearly" : {
               "days_to_backup" : [100],
               "delete_after" : 14,
               "compressed" : true,
           "path" : "localhost"
          }
}
{
    "_id":2,
    "db_name":"test",
    "username":"test_user",
    "password":"test_pass",
    "daily" : {
               "days_to_backup" : [1,7],
               "delete_after" : 14,
               "compressed" : true,
           "path" : "localhost"
           },

    "monthly" : {
               "days_to_backup" : [2,5,25],
               "delete_after" : 7,
               "compressed" : false,
           "path" : "localhost"
           },

    "yearly" : {
               "days_to_backup" : [50],
               "delete_after" : 14,
               "compressed" : true,
           "path" : "localhost"
           }


}

Now once user run the script with particular database name, i want to loop through the "days_to_backup" numbers and for each day look it it's equal for today date. The problem is that i don't know how to fetch the daily/monthly/yealy.days_to_backup and then loop through the days. I tried with jq :

#! /bin/sh

#monday is first day of the week
export Today=$(date +%d)
while getopts d: flag
do
    case "${flag}" in
        d) database=${OPTARG};;


    esac
done

if jq .db_name file.json | grep $database
then
        jq 'select(.db_name=="'$database'")' file.json
        ##this one returns the whole document of the specified database
        ##loop here for daily/monthly_yearly.days_to_backup???
else
        echo "database not found"
fi

Edit: my input is the name of the database ( " postgres " ) and then i will iterate through the daily/monthly/yearly array and if the number is like current date ( today is 8 of the month) so the output will be - echo "backup today".

Edit2: sorry my bad. for daily it means that day of the week so (1,7) are sunday and saturday and if current date is sunday or saturday i want and echo "backup today". for monthly it means the day of the month, so if i have monthly (01,08) it will echo "backup today" because today is the 8th of the month. and for yearly i want days since the first day of the year.

Ok so I succeeded to loop through the array but the problem now is that it run over the array of the 2 big objects (id 1 + 2)

for i in $(jq -r ".daily.days_to_backup | .[]" file.json)
  do
    echo $i "im number"
  done

how do I select that it will run only over _id:1 / db_name: postgres?

9
  • Please add to your question example input and your desired output (no description). Commented Nov 8, 2020 at 15:24
  • Does this mean that on the 29th of each month you're supposed to do a daily backup and a yearly backup, and on the 30th you're supposed to do a monthly backup? Commented Nov 8, 2020 at 15:29
  • edited. when I call the script i specify with -d the name of the database and then for each daily/monthly/yearly.days_to_Backup array i want to check if the number there is same as current date. if yes just print a echo that it's same date. Commented Nov 8, 2020 at 15:30
  • You have to be a bit careful with date +%d -- for single digit days, you get a leading zero, which might throw off your comparisons. Commented Nov 8, 2020 at 15:31
  • You might find gron a bit easier to work with than jq Commented Nov 8, 2020 at 15:32

1 Answer 1

3

An efficient approach would be based on using any, e.g. along the lines of the following:

jq --arg db $database --argjson Today $Today '
    select(.db_name==$db and
           any(.daily[], .monthly[], .yearly[]; . == $Today) ) 
' file.json

Note that both parameters ($database and $Today) should be passed in as command-line arguments rather than provided using shell-based string interpolation. Using --argjson will ensure that any leading 0s in the shell variable $Today do not cause problems.

Note also that the above query will return a stream of 0 or more values. You might want to guarantee the names are distinct, e.g. by using the jq built-in filter unique (defined for arrays), or the stream-oriented filter uniques defined in the jq Cookbook.

Sign up to request clarification or add additional context in comments.

4 Comments

Could you please explain how . can be equal to $Today which is a number ?
Using --argjson will in this case ensure Today is a JSON number.
But . is a whole struecture.
Nope. Look at the definition of any/2 in builtin.jq

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.