4

I'm trying to figure out how to pass a comma , separated list as inputs and to have my function process the values one at a time.

My function:

addToWhitelist ()
{
   host='127.0.0.1'
   db='mytest'
   _mongo=$(which mongo);
   echo "${_ip}";
   read -a arr <<<${_ip};
   for i in ${arr[@]};
   do
     exp="db.account.update({\"account\":'${_account}'},{\$addToSet:{\"ip_list\": {\$each:['${_ip}'] }}})";
     ${_mongo} ${host}/${db} --eval "$exp"
   done
}

I run my script like this:

./myscript.sh -m add -a pizzahut -i 123.456.790.007,123.456.790.008

My code in progress:

#!/usr/local/bin/bash
set -e
set -x

# Usage for getopts
usage () {
    echo "Example: $0 -m find -a pizzahut"
    echo "Example: $0 -m add -a pizzahut -i 10.10.123.456"
    exit 1;
}

while getopts ":m:a:i:" o; do
  case "${o}" in
    m)
    _mode=${OPTARG}
         if [[ "${_mode}" != find && "${_mode}" != add ]]; then
        usage
        fi
    ;;
    a)
    _account=${OPTARG}
    ;;
    i)
    _ip=${OPTARG}
        set -f
        IFS=,
    ;;
    *)
       usage
       ;;
  esac
done
shift $((OPTIND-1))


getWhitelist ()
{
   host='127.0.0.1'
   db='mytest'
   _mongo=$(which mongo);
   exp="db.account.find({\"account\":'${_account}'},{ip_list: 1}).pretty();";
   ${_mongo} ${host}/${db} --eval "$exp"
}

# Read a list
addToWhitelist ()
{
   host='127.0.0.1'
   db='mytest'
   _mongo=$(which mongo);
   echo "${_ip}";
   read -a arr <<<${_ip};
   for i in ${arr[@]};
   do
     exp="db.account.update({\"account\":'${_account}'},{\$addToSet:{\"ip_list\": {\$each:['${_ip}'] }}})";
     ${_mongo} ${host}/${db} --eval "$exp"
   done
}


case "${_mode}" in
  'find')
      echo "Finding information for the account ${_account}"
      getWhitelist
      ;;
  'add')
      echo "Adding the following IP: ${_ip}"
      addToWhitelist
      ;;
esac

set +x

However, the problem I'm having when I call that function is that inserts the values as a single string:

  "ip_list" : [
    "123.456.790.006",
    "123.456.790.007,123.456.790.008",
    "123.456.790.009"
  ]
}

Expecting:

  "ip_list" : [
    "123.456.790.006",
    "123.456.790.007",
    "123.456.790.008",
    "123.456.790.009"
  ]
}
noober
  • 1,427
  • 3
  • 23
  • 36

2 Answers2

2

Since your script receives a comma-separated list of IPs, effectively something like:

_ip="123.456.790.007,123.456.790.008"

you need to split the list by , and wrap each IP with quotes before giving it to Mongo's $each operator.

First, localize redefinition of IFS to the read command only, then exploit printf's behaviour of reusing the same format string when more arguments are provided (the expanded array "${arr[@]}"), store the result to a variable via -v option, and strip the leading , from the result:

IFS=, read -a arr <<<"${_ip}"
printf -v ips ',"%s"' "${arr[@]}"
ips="${ips:1}"

For the _ip value given above, this script will store in ips variable:

"123.456.790.007","123.456.790.008"

So, applying this to your program, first change your i) case like:

case "${o}" in
    # ...
    i) _ip=${OPTARG};;
esac

then fix the addToWhitelist function:

addToWhitelist() {
    host='127.0.0.1'
    db='mytest'
    _mongo=$(which mongo)
    IFS=, read -a arr <<<"${_ip}"
    printf -v ips ',"%s"' "${arr[@]}"
    ips="${ips:1}"
    exp="db.account.update({'account': '${_account}'}, {\$addToSet:{'ip_list': {\$each:[$ips]}}})";
    "${_mongo}" "${host}/${db}" --eval "$exp"
}
randomir
  • 17,989
  • 1
  • 40
  • 55
  • 1
    Wow! Thank you so much for your help with this. Using the `printf` was a nice way to handle that. I appreciate your help! – noober Oct 19 '17 at 03:45
1

Try below,

ip=$(echo ${OPTARG}|sed "s/,/,\n/g")

So the complete script will come like this,

#!/usr/local/bin/bash
set -e
set -x

# Usage for getopts
usage () {
    echo "Example: $0 -m find -a pizzahut"
    echo "Example: $0 -m add -a pizzahut -i 10.10.123.456"
    exit 1;
}

while getopts ":m:a:i:" o; do
  case "${o}" in
    m)
    _mode=${OPTARG}
         if [[ "${_mode}" != find && "${_mode}" != add ]]; then
        usage
        fi
    ;;
    a)
    _account=${OPTARG}
    ;;
     i)
    _ip=$(echo ${OPTARG}|sed "s/,/,\n/g")
        set -f
        IFS=,
    ;;
    *)
       usage
       ;;
  esac
done
shift $((OPTIND-1))
getWhitelist ()
{
   host='127.0.0.1'
   db='mytest'
   _mongo=$(which mongo);
   exp="db.account.find({\"account\":'${_account}'},{ip_list: 1}).pretty();";
   ${_mongo} ${host}/${db} --eval "$exp"
}

# Read a list
addToWhitelist ()
{
   host='127.0.0.1'
   db='mytest'
   _mongo=$(which mongo);
   echo "${_ip}";
   read -a arr <<<${_ip};
   for i in ${arr[@]};
   do
   exp="db.account.update({\"account\":'${_account}'},{\$addToSet:{\"ip_list\": {\$each:['${_ip}'] }}})";
     ${_mongo} ${host}/${db} --eval "$exp"
   done
}


case "${_mode}" in
  'find')
      echo "Finding information for the account ${_account}"
      getWhitelist
      ;;
  'add')
   echo "Adding the following IP: ${_ip}"
      addToWhitelist
      ;;
esac

set +x
Riyas Siddikk
  • 186
  • 2
  • 11