Counting JSON Occurrences in Bash Without Syntax Errors on Remote Servers

If you’re working with JSON data in shell scripts and need to count occurrences of a specific value (e.g., “pending”) using Bash, you might encounter a surprising syntax error—especially when executing the command remotely over SSH or inside a CI/CD pipeline.

Here’s a real-world example. Suppose you have a JSON string stored in a Bash variable and want to count how many times "pending" appears inside it.

You might be tempted to write:

echo "${jsonString}" | sed 's/},{/}\n{/g' > output1.txt
numberOfTransactions=$(grep -o 'pending' output1.txt | wc -l)
echo "$numberOfTransactions"

This works locally. However, when you run it remotely like:

ssh user@server "
echo \"${jsonString}\" | sed 's/},{/}\n{/g' > output1.txt
numberOfTransactions=\$(grep -o 'pending' output1.txt | wc -l)
echo \"\$numberOfTransactions\"
"

You may encounter:

bash: -c: line 0: syntax error near unexpected token `('

Why does this happen?

The issue occurs because:

  • Parentheses () are special characters in Bash.
  • When wrapped in multiple levels of quotes (SSH, CI/CD), Bash misinterprets unescaped characters.
  • The $(...) syntax for command substitution inside a double-quoted string must be escaped as \$(...).

Without proper escaping, Bash thinks the parenthesis is unexpected.


How to fix it?

To avoid this syntax error, you need to:

  1. Escape each $( as \$( in the SSH command.
  2. Separate commands with semicolons (;) inside the string.
  3. Or—best practice—move the logic to a script file and execute the file remotely.

Here’s a corrected single-line solution:

ssh user@server "
echo \"\${jsonString}\" | sed 's/},{/}\n{/g' > output1.txt;
numberOfTransactions=\$(grep -o 'pending' output1.txt | wc -l);
echo \"\$numberOfTransactions\"
"

Alternatively, to avoid temporary files and use piping only:

ssh user@server "
echo \"\${jsonString}\" | sed 's/},{/}\n{/g' | grep -o 'pending' | wc -l
"

Key takeaways:

Always escape $() as \$() in nested quotes.
Use ; to separate commands inside an SSH string.
Move complex commands to a script file for clarity and safety.


Bonus: Using jq for JSON parsing

Instead of relying on grep and sed, consider using jq for JSON parsing:

echo "${jsonString}" | jq '[.. | .bookingStatus? | select(. == "pending")] | length'

This method is safer and more accurate.


Conclusion

Handling JSON data inside Bash scripts—especially over remote execution—requires careful quoting and escaping. By following best practices, you can avoid syntax errors and write more maintainable scripts.

For production environments, consider using dedicated JSON tools like jq to avoid brittle text parsing.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back