3

I'm aware that, in PowerShell, backticks(`) are used to escape characters instead of the backslash(\). Hence, when using sed, this:

echo '"where am I"' | sed "s/\"[^\"]*\"/\033[96m&\033[0m/g;"

will not work and I would have to write it like this:

echo '"where am I"' | sed "s/`"[^\`"]*`"/`e[96m&`e[0m/g;"

Hence, I would like to do the same with this code:

echo '[where am I]' | sed "s/\[\([^09]\)/\033[94m[\033[0m\1/g;"

The expected output should be:

enter image description here

However, when I tried to replace all the backslashes(\) with backticks(`), I can't seem to get the expected output as you can see below:

enter image description here

Any help would be appreciated. Thanks in advance.

digitalguy99
  • 443
  • 4
  • 13
  • @MikeAnthony I'm using the code to build a program that colors my `ghci` output, you can find the full code [here](https://pastebin.com/YUE2cFnR). – digitalguy99 Apr 22 '22 at 00:34

2 Answers2

2

As far as I'm aware, GNU sed doesn't support octal escape sequences - such as \033 to represent an ESC char. - only hexadecimal ones - such as \x1b.

The following command, which uses hex. escape sequences, should therefore work in both POSIX-compatible shells and in PowerShell:

# Note: Requires *GNU* sed
(echo '[where am I]' | sed 's/\[\([^09]\)/\x1b[94m[\x1b[0m\1/g')

In other words:

  • Because the entire, verbatim string ('...') is interpreted by sed itself, there is no need for PowerShell's string interpolation (via "...").

Note:

  • The enclosing (...), which on Windows is required for Windows PowerShell to properly render the ANSI escape codes / VT (Virtual Terminal) sequences in the terminal (console) - see this answer. It isn't needed if you capture the output in a variable or redirect it.

  • In PowerShell, use of echo - a built in alias of the Write-Output cmdlet - isn't necessary and can be omitted, due to PowerShell's implicit output behavior.


If your sed implementation doesn't support escape sequences such as \x1b - such as on macOS - you must indeed resort to using PowerShell's escape sequences inside an expandable (double-quoted) string ("..."); that is, you must replace \x1b with escape sequence `e in order to embed a verbatim ESC character into the string, up front (in Windows PowerShell, which doesn't support `e, use subexpression $([char] 0x1b) instead):

# Note: `e only works in PowerShell (Core) 7+
#       In Windows PowerShell, use $([char] 0x1b)
(echo '[where am I]' | sed "s/\[\([^09]\)/`e[94m[`e[0m\1/g")

Important: The above commands contain no embedded " characters, which avoids a long-standing PowerShell bug that is still present as of PowerShell (Core) 7.2.2:

  • The need to unconditionally, manually \-escape embedded " chars. in arguments passed to external programs - see this answer for details.

  • A few quick examples that print verbatim 3" of snow:

    # Up to at least PowerShell 7.2.2:
    # Without escaping the embedded " with \ (too), 
    # they would in effect be removed from the arguments.
    # Note that pipeline input is *not* affected.
    
    '3" of snow' | findstr '\"'  # Windows
    /bin/echo '3\" of snow'      # Unix
    
    # In expandable (double-quoted) strings, you therefore must escape *twice*:
    # once for PowerShell, then for the external-program call.
    '3" of snow' | findstr "\`""  # Windows
    /bin/echo "3\`" of snow"      # Unix
    
mklement0
  • 382,024
  • 64
  • 607
  • 775
0

You can pass non-interpolated expression strings to sed by using single quotes, '; e.g., 'a non-interpolated string'. instead of double quotes around the text. sed would take what it normally does for input. When you use double quotes, that's when powershell escaping comes into play.

Anyway, an alternative to sed would be leveraging the regular expression substitution built into powershell. For instance,

Write-Output ('[where am i]' -replace '\[(.*?)\]', "<<`e[5;36m`$1`e[0m>>")

Will capture the text between square brackets and place it between "chevrons" and make it blink.

Here's an article on inserting ANSI in text using powershell.

Todd
  • 4,669
  • 1
  • 22
  • 30