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

  curl \
  -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 script.sh file, which is called with sudo ./script.sh

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.

  • Interesting detail: using -H "If-Match: $(echo $etag)" works. I have no clue why this could be and only stumpled upon it by trying different random things in desperation.
    – Concerto
    Mar 19 at 17:49
  • You are correct, yes! It has a trailing line break character. Do want to add your suggestion as an answer?
    – Concerto
    Mar 19 at 18:21
  • \r is the carriage return, not a newline... It's usually not in IFS by default, so word splitting actually shouldn't remove it. E.g. on my Mac and Debian, var=$(echo $'foo\r\n'); printf "<%q>\n" $(echo $var) prints <$'foo\r'>. Hmm.
    – ilkkachu
    Mar 19 at 18:28
  • I see... var=$(echo $'foo\r\n'); printf "<%q>\n" $(echo $var | tr -d '\r') does however remove the carriage return. I couldn't tell exactly what the semantic difference is in this case, but the latter option returns a valid response...
    – Concerto
    Mar 19 at 18:39
  • Yep. Doesn't matter though, if removing the CR with tr fixes it.
    – ilkkachu
    Mar 19 at 18:46

1 Answer 1


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.

  • Whether [a-zA-Z0-9]+ matches only alphanumerics depends on the locale. On a typical locale on a GNU system, it matches on hundreds of characters not classified as alphanumeric such as ₨℀℁℃℅℆℉№℠℡™℻⅍㉗㉘㉙㉚㉛㉜🆐🆑🆒🆓🆔🆕🆖🆗🆘🆙 and of course misses thousands of alnums in non-latin scripts. Mar 19 at 19:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .