Passing ETag as Bash Variable to cURL

I’m struggling passing my etag to cURL and getting a successful response. I get the etag with:

  -u $token 
  -H "Accept: application/json" 
  "$api_url/domain-types/activation_run/collections/pending_changes" | awk '/^ETag:/ { print $2 }'

I have verified that this returns the correct etag. However the following cURL request fails:

curl -v -L 
  -u $token 
  -H "Accept: application/json" 
  -H "If-Match: $etag" 
  -H "Content-Type: application/json" 
  -d "{
        "sites": [

And the problem here is the line -H "If-Match: $etag, if I pass the etag as a literal string (enquoted or not), I get a valid response. For reference, ${etag}, "$etag", putting it in a file and calling it with @etag.txt and so on doesn’t work either.

This is the error response:

<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
<address> ... </address>

The code snippets above are all located in a file, which is called with sudo ./

I’m working with the REST API from CheckMK.

Edit: Indeed: On printf "etag <%q>n" "$etag" I get etag <$'"e3asdajldlskj..."r'>. Adding to the etag declaration | tr -d 'r' and in the cURL request using $etag solves the problem.

Asked By: Concerto


In cases like this, it helps to check if there’s something invisible in the value you get. Like extra whitespace, or a trailing newline or such.

Here, etag was set from a command substitution, which removes trailing newlines, so it shouldn’t be that, but in some other cases you might get one.

To check, use e.g. printf "etag <%q>n" "$etag". The %q specifier should work at least in Bash to print the value quoted/escaped so that any whitespace is visible.

Then, remove the extras, depending on what you see you have.

You showed having a trailing carriage return r, and that could be removed within the shell in Bash with:


(I can’t see how passing through $(echo $etag) would help with a CR, though, unless you have IFS explicitly set to contain one.)

More generally, if you know you want e.g. only alphanumerics from the original command, you could pipe the output through tr to remove anything except those:

etag=$(curl ... | tr -dc 'a-zA-Z0-9')

(-c for taking the complement of the given set, -d for deleting the matching chars.)

Of course that would also remove any whitespace from the middle, etc.

In Bash, you could also do something like

[[ $etag =~ [a-zA-Z0-9]+ ]] && etag="$BASH_REMATCH"

to find the leftmost string of alphanumerics from the value, and to use that.

Answered By: ilkkachu
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.