0

So I'm having a problem with a script used to automatically create shard replica sets in MongoDB.

The script is as follows:

#!/bin/bash

set -x

export shard_ips='[10.0.0.206,10.0.0.142,10.0.0.234]'

export shard_count=3

export replication_set_number=1

shard_count=$((shard_count-1))

IFS="," read -a shard_ips_arr <<< $(echo $shard_ips | tr -d '[]')

primary_shard_ip=${shard_ips_arr[0]}

count=0
while [ $count -le ${shard_count} ]
do
  shard_ips_arr[$count]=$(echo { _id: $count, host: \"${shard_ips_arr[$count]}:27017\" } )
  count=$(($count + 1))
done
function join { local IFS="$1"; shift; echo "$*"; }

shard_ips_arr=$(join , "${shard_ips_arr[@]}")

echo "${shard_ips_arr}"

echo "mongo --eval 'rs.initiate( { _id: \"shardreplset${replication_set_number}\", members: [ ${shard_ips_arr} ] } )' ${primary_shard_ip}:27017"

mongo --eval 'rs.initiate( { _id: "'shardreplset${replication_set_number}'", members: [ '${shard_ips_arr}' ] } )' ${primary_shard_ip}:27017

The purpose of the above script is to take in a string array passed from terraform and convert it into something that MongoDB can understand. A complete command should look like:

mongo --eval 'rs.initiate( { _id: "shardreplset1", members: [ { _id: 0, host: "10.0.0.206:27017" },{ _id: 1, host: "10.0.0.142:27017" },{ _id: 2, host: "10.0.0.234:27017" } ] } )' 10.0.0.206:27017

This will create a replica set of the three MongoDB servers using the primary shard (10.0.0.206:27017).

The issue is the inclusion of single quotes that bash seems to add to the variables. The debug output (using set -x) I receive from the last line of the script is as follows:

+ mongo --eval 'rs.initiate( { _id: "shardreplset1", members: [ {' _id: 0, host: '"10.0.0.206:27017"' '},{' _id: 1, host: '"10.0.0.142:27017"' '},{' _id: 2, host: '"10.0.0.234:27017"' '} ] } )' 10.0.0.206:27017

See all those extra single quotes in each item of $shard_ips_arr? Example:

{' _id: 0, host: '"10.0.0.206:27017"' '} should look like { _id: 0, host: "10.0.0.206:27017" }

Does anyone know how to solve this issue?

And if you don't think that the single quotes are actually the issue, please let me know as well.

Please do also let me know if you want anything else clarifying.

  • [quotes don't nest](https://stackoverflow.com/questions/28458437/single-quotes-within-single-quotes-issue-bash-command-line-gnu-parallel) – user1934428 Sep 23 '21 at 08:28
  • @user1934428 I kind of get what's going on there but it is a GNU parallel example and the work around doesn't really make sense to me. I now understand that nesting single quotes is an issue, It's a work around I'm looking for. Edit: If you simply remove the single quotes around the variables then you get: mongo --eval 'rs.initiate( { _id: "shardreplset${replication_set_number}", members: [ ${shard_ips_arr} ] } )' 10.0.0.206:27017 as debug output – Matthew Mcloughlin Sep 23 '21 at 08:52
  • See it from this way: In theory, you don't need quotes at all, because you can escape explicitly individual characters using `\`. The quotes are just handy way to spare you typing a \ in front over, say, any space inside. So, for a starting point, start with just one set of quotes outside, and if you need that quote inside, escape it. You perhaps won't end up with the most elegant solution, but it should work at least. – user1934428 Sep 23 '21 at 08:56
  • @user1934428 I'm not worried about the solution being particularly elegant. I get in theory quotes aren't necessary, it's just that the way that the mongo command is formatted requires single quotes around the command after --eval. This means the variables within that command can't be accessed unless they are enclosed in single quotes of their own. But then this is what is causing the issue I believe. Bash sees nested quotes and I don't know how to fix that. I've tried combinations of escaping things but can't figure it out. Thank you for your help so far. – Matthew Mcloughlin Sep 23 '21 at 09:05
  • 1
    Mongo can't even see the single quotes just **after** the `--eval`. bash is consuming them. If you are sure that Mongo needs to receive quotes in the parameter, you could have it as `--eval '\'whatever else you need here\''`. The outer single quotes are for bash, and the escaped ones are passed to the invoked command. – user1934428 Sep 23 '21 at 09:08
  • BTW, this script has several other quoting and variable usage problems (for example, depending on the files that exist in the working directory, `echo $shard_ips` may print a list of filenames instead of what you expect). I recommend running it through [shellcheck.net](https://www.shellcheck.net), and fixing what that points out. – Gordon Davisson Sep 23 '21 at 09:14
  • @user1934428 Just produces this error output: ./create_shard_replica_set.sh: line 40: syntax error near unexpected token (' ./create_shard_replica_set.sh: line 40: mongo --eval '\'rs.initiate( { _id: "shardreplset${replication_set_number}", members: [ ${shard_ips_arr} ] } )\'' ${primary_shard_ip}:27017' – Matthew Mcloughlin Sep 23 '21 at 09:15
  • @MatthewMcloughlin : Add this information (the code you are using, plus the error message you get) to your question, not into a comment. Also, follow the advice by Gordon Davisson. – user1934428 Sep 23 '21 at 09:18
  • @user1934428 Thanks for all your help. Was simply a syntax error in an earlier line is seems! Feel dumb for that now but thanks for sticking with me. – Matthew Mcloughlin Sep 23 '21 at 10:01
  • @GordonDavisson Thank you very much for the resource. It spotted a syntax/semantic error that I hadn't spotted and fixed problems later on. I'll be sure to use shellcheck in future. – Matthew Mcloughlin Sep 23 '21 at 10:02

0 Answers0