Hex codes in sed - not behaving as expected on OSX

hex, macos, sed

Solution

There is no general concept of what "the OS and its functions understand" -- each program, function, etc understands its own particular set of metacharacters, escapes, etc. And it just happens that `sed` doesn't do hex codes. But bash does (if you ask it to), so you can have it translate them before calling `sed` with `$''`:

$ echo A | sed $'s/\x41/B/'
B

Note that this also interprets other escape sequences before passing them to `sed`, so if you want to pass any escapes to `sed`, you need to double-escape them, or switch quote modes so only the relevant portion is in `$''`:

$ echo A | sed $'s/\\(\x41\\)/B\\1/' # double-escapes for sed's escape sequences
BA
$ echo A | sed 's/\('$'\x41''\)/B\1/' # equivalent with different quote modes
BA
$ echo A | sed 's/\(A\)/B\1/' # simplest equivalent version
BA

And if you want to interpret a hex escapes in a variable, rather than constant, string, then you pretty much have to use the shell's `printf` builtin:

$ hex=41
$ echo A | sed "s/$(printf "\x$hex")/B/"
B

Problem

The answer to my question may exist on SO, but I have honestly looked hard and can't find it. The closest I got was this Q&A but I could not reproduce their results on my machine (OSX 10.7.5, using `bash`). Here is the issue reduced to its essence: I can't get `sed` to interpret `\xnn` (e.g. `\x41` for `A`) as hex characters. What's driving me nuts in particular is this: ``` echo -e '\x41' ``` results in `A` - so the OS and its functions understand my hex code... ``` echo -e '\x41' | sed 's/A/B/' ``` results in `B` - as expected, since the hex code was converted to `A` before `sed` saw it But ``` echo A | sed 's/\x41/B/' ``` results in `A` - I would have expected `B` I have tried things like ``` echo A | LANG='C' sed 's/\x41/B/' ``` results in `A` ``` echo A | LANG='' sed 's/\x41/B/' ``` ditto... ``` echo A | sed 's/[\x41]/B/' ``` results in `A` BUT... ``` echo A | sed 's/[\x41-\x41]/B/' ``` results in `B` ??? Am I being completely stupid? Or is there really something strange with `sed`? It can apparently interpret the hex code in a range, but I can't get it to be interpreted as a single character. What am I missing? Please note - I am looking for answers that both explain why the above is behaving the way it is, and for ways to make it possible to insert a single hex code anywhere in a `sed` string, on the OSX platform. This means both in the "search", and in the "replace" part of the `s/` command. Because I have obviously shown I can search for a single character with [\xnn-\xnn]; that's not the answer I am looking for. Thanks in advance!

Original source

Related problems