<p>I have the following <a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/" rel="nofollow noreferrer">Kubernets CronJob</a> definition:</p>
<pre><code>apiVersion: batch/v1
kind: CronJob
metadata:
  name: myCronJob
spec:
  schedule: &quot;*/1 * * * *&quot;
  failedJobsHistoryLimit: 1
  successfulJobsHistoryLimit: 1
  jobTemplate:
    spec:
      backoffLimit: 2
      parallelism: 1
      template:
        metadata:
          annotations:
            linkerd.io/inject: disabled
        spec:
          containers:
            - name: myCronJob
              image: curlimages/curl:7.72.0
              env:
                - name: CURRENT_TIME
                  value: $(date +&quot;%Y-%m-%dT%H:%M:%S.%sZ&quot;)
              args:
                - /bin/sh
                - -ec
                - &quot;curl --request POST --header 'Content-type: application/json' -d '{\&quot;Label\&quot;:\&quot;myServiceBusLabel\&quot;,\&quot;Data\&quot;:\&quot;{\'TimeStamp\':\'$(echo $CURRENT_TIME)\'}\&quot;,\&quot;QueueName\&quot;:\&quot;myServiceBusQueue\&quot;}' https://mycronjobproxy.net/api/HttpTrigger?code=mySecretCode&quot;
          restartPolicy: OnFailure
</code></pre>
<p>Notice I pass a dynamic date to <code>curl</code> via an environment variable, as described <a href="https://stackoverflow.com/a/58192064/195964">here</a>.</p>
<p>However, this produces an error at runtime (copied from K9s):</p>
<pre><code>curl: (3) unmatched close brace/bracket in URL position 26:                                                                                                                    
+&quot;%Y-%m-%dT%H:%M:%S.%sZ&quot;)}&quot;,&quot;QueueName&quot;:&quot;myServiceBusQueue&quot;}
                         ^
</code></pre>
<p>I suspect this is likely an issue with combining double- and single quotes and escape characters. The <code>curl</code> command runs fine locally on macOS, but not when deployed using the <code>curlimages/curl:7.72.0</code>. There seems to be some difference in behavior.</p>
<p>On macOS, on my local dev machine, I can run the command like so:</p>
<pre><code>curl --request POST --header &quot;Content-type: application/json&quot; -d &quot;{'Label':'myServiceBusLabel','Data':{'TimeStamp':'$(echo $CURRENT_TIME)'},'QueueName':'myServiceBusQueue'}&quot; https://mycronjobproxy.net/api/HttpTrigger?code=mySecretCode
</code></pre>
<p>Output:</p>
<pre><code>Message was successfully sent using the following params: Label = myServiceBusLabel | Data = {&quot;TimeStamp&quot;: &quot;2023-05-15T15:44:45.1684158285Z&quot;} | QueueName = myServiceBusQueue%
</code></pre>
<p>But when I use that version in my K8s CronJob YAML file, my IDE (JetBrains Rider) says: &quot;Scalar value expected.&quot; It seems like the whole command must be enclosed in double quotes.</p>
<p>What is the correct way to quote/escape this <code>curl</code> command?</p>

leifericf
<p>The requirement for <code>sh -c</code> is that whatever command you want it to run must be passed in a single argument.  With the list-form <code>args:</code>, you're explicitly specifying the argument list, and you can use any YAML string syntax so long as it is in a single list item.</p>
<p>The first thing this means is that you don't need the outermost set of double quotes.  That can be useful to disambiguate some kinds of structures and values – <code>&quot;true&quot;</code>, <code>&quot;17&quot;</code> – but in this case the item is pretty clearly a string and not something else.  This removes a layer of quoting.</p>
<p>This also means alternate YAML syntaxes are available here.  Given the sheer length of this line, I might look at using a <a href="https://yaml.org/spec/1.2.2/#813-folded-style" rel="nofollow noreferrer">folded block scalar</a> here: if the list item value is just <code>&gt;-</code> at the end of the line, then the following (indented) lines will be combined together with a single space (<code>&gt;</code>) and there will not be a final newline (<code>-</code>).</p>
<p>Kubernetes doesn't do command substitution in <code>env:</code>.  If you want an environment variable to hold a dynamic value like this, it needs to be embedded or computed in the command in some form.  Since you're already using <code>sh -c</code> syntax you need to add that into the command string.</p>
<p>There is one shell-syntax concern here as well.  In your example, the <code>curl -d</code> argument is a single-quoted string <code>curl -d '{...}'</code>.  Within that single-quoted string, command substitution and other shell processing doesn't happen.  You need to change these single quotes to double quotes, which means you need to escape the double quotes in the JSON body; but if we remove the YAML double quotes as well, it is only single escaping.  You also then don't need to quote the single quotes inside this string.</p>
<p>(While we're here, don't <code>$(echo $VARIABLE)</code>, just use <code>$VARIABLE</code> directly.)</p>
<p>This should all combine to form:</p>
<pre class="lang-yaml prettyprint-override"><code>args:
  - /bin/sh
  - -ec
  - &gt;-
      CURRENT_TIME=$(date +&quot;%Y-%m-%dT%H:%M:%S.%sZ&quot;);
      curl
        --request POST
        --header 'Content-type: application/json'
        -d &quot;{\&quot;Label\&quot;:\&quot;myServiceBusLabel\&quot;,\&quot;Data\&quot;:\&quot;{'TimeStamp':'$CURRENT_TIME'}\&quot;,\&quot;QueueName\&quot;:\&quot;myServiceBusQueue\&quot;}&quot;
        https://mycronjobproxy.net/api/HttpTrigger\?code=mySecretCode
</code></pre>
<p>So note that we have two commands, explicitly separated with a semicolon (at the end of the first line).  The <code>curl</code> arguments are split out one to a line for readability but with no additional punctuation (no backslashes at the ends of lines).  The <code>-d</code> option is double-quoted so the variable expansion happens; the single quotes inside the double-quoted string are not escaped.</p>
<hr />
<p>Is the <code>Data</code> field itself intended to be a JSON object serialized as a string?  In that case you will need to use double quotes inside of a double-quoted JSON string inside a double-quotes shell argument.  The layers of escaping would look like:</p>
<ol>
<li>Create the innermost JSON-string argument
<pre class="lang-json prettyprint-override"><code>{&quot;TimeStamp&quot;:&quot;$CURRENT_TIME&quot;}
</code></pre>
</li>
<li>Embed that in a JSON string and serialize it, which means escaping the double quotes
<pre class="lang-json prettyprint-override"><code>{&quot;Data&quot;:&quot;{\&quot;TimeStamp\&quot;:\&quot;$CURRENT_TIME\&quot;}&quot;}
</code></pre>
</li>
<li>Embed that in a shell string, escaping both the double quotes and backslashes
<pre class="lang-bash prettyprint-override"><code>-d &quot;{\&quot;Data\&quot;:\&quot;{\\\&quot;TimeStamp\\\&quot;:\\\&quot;$CURRENT_TIME\\\&quot;}\&quot;}&quot;
</code></pre>
</li>
</ol>
<p>It might be more straightforward to use a tool like <code>jq</code> to construct or manipulate the JSON, or to put a template string in a ConfigMap and then use <code>sed</code> or <code>envsubst</code> to replace the dynamic value.</p>
