bashgcloudgoogle-cloud-pubsubcommand-substitution

Pass contents of file as a string to an argument for another command


I have a json file like this:

{"my_string": "apple", "my_int": 456}

And a Bash program that works OK like this:

my_program --message='{"my_string": "apple", "my_int": 456}'

But when my JSON is a file I cannot seem to get it to run properly:

my_program --message=$(cat test_message.json) 

I've been searching SO looking at similar questions and have tried lots of things like tr, awk, and various combinations of echo and cat but to no avail.

This is the error I receive that leads me to believe this is something I am doing wrong in Bash:

ERROR: (gcloud.beta.pubsub.schemas.validate-message) unrecognized arguments:
  "apple",
  "my_int":
  456}
  To search the help text of gcloud commands, run:
  gcloud help -- SEARCH_TERMS

If you see it look like it has broken the JSON up, only taking the characters before the first space. Any ideas? I have a feeling this is very basic but I can't seem to figure it out. Thank you in advance.


Solution

  • The immediate fix is to add quotes around the command substitution:

    my_program --message="$(cat test_message.json)"
    

    See also When to wrap quotes around a shell variable?

    However, a much better fix if you have control over my_program is to have it read standard input instead.

    my_program --stdin <test_message.json
    

    If the cat is just a placeholder for something more complex, combine with a pipe:

    jq .fnord test_message.json |
    my_program --stdin
    

    (Maybe still better to not require an explicit option for this common base case.)

    In case it's not obvious, the pipe is a direct line of communication between the producer and the consumer, whereas the command substitution requires the shell to read and buffer into memory all the output before passing it on. This is inefficient, inelegant, and slow and error-prone for any nontrivial amounts of output.