'revealing' hidden/control 'codes' in strings in bash
Asked Answered
S

1

6

There a very handy function in Python: repr() which when applied on a string containing blank characters will print out a representation of that string that cannot lead to any human misinterpretation of the string actual content.

for instance:

$ python -c "print repr(r'''abcde\rfghi\tjklmn\nopqr\bstuv\fwxyz''')"
'abcde\\rfghi\\tjklmn\\nopqr\\bstuv\\fwxyz'

How can I do the same in bash with printf?

The perfect tool/trick I'm looking for would literally print

'abcd\refjh\bijk'

for the command

printf "abcd\refjh\bijk" | <something>

The intent behind this is to improve a test tool that prints differences betweens two strings:

http_response_code=$(curl -s --head http://httpbin.org/ | head -1)  # will put "HTTP/1.1 200 OK\r" in $http_response_code
assert_equal "HTTP/1.1 200 OK" "$http_response_code"
> failed: strings do not match
> expected:   'HTTP/1.1 200 OK'
> actual:     'HTTP/1.1 200 OK'

As you can see, the current implementation let the user clueless and quite confused about the reasons of the failure.

Idealy I'd like to have the following output instead:

> failed: strings do not match
> expected:   'HTTP/1.1 200 OK'
> actual:     'HTTP/1.1 200 OK\r'

Current tries:

  • printf $'\a\b\e\E\f\n\r\t\v\\\'\"' | cat -A
  • echo $'\a\b\e\E\f\n\r\t\v\\\'\"' | cat -A | sed -r '$!{ N;s/\$\n/\\n/;t sub-yes;:sub-not;P;D;:sub-yes;}'
  • printf $'\a\b\e\E\f\n\r\t\v\\\'\"' | od -c
Shend answered 12/9, 2015 at 20:25 Comment(8)
echo does print the '\r' character itself and not its human representation \r. So the result is just that the caret is sent to the beginning of the line, but that, the use cannot see.Shend
Sorry, not clear - when I do: TSTR="abcd\refjh\bijk" and then echo "## ${TSTR} ##" - I get literal output; If I use 'printf' then, yes CR overwrites. This is with Linux/Bash, yes?Cordiform
you're right, that works in the shell. I guess in the software I use the use of printf does complicate all this :/Shend
Try using two '\' in your string, i.e.replace single '\' with '\\' with your tool's string functions.Cordiform
the issue is that I have no control on those strings, I work only with variables that might happen to have those blank characters I'd like literally printedShend
Ok, then real question is about 'revealing' hidden/control 'codes' in strings; Is your String being access via Bash/other_shell - if so then pipes might work (I,e, printf ${VAR} | cat -v # or cat -v -eCordiform
not that bad :) printf $'\a\b\e\E\f\n\r\t\v\\\'\"' | cat -ve^G^H^[^[^L$ on the 1st line and a 2nd line with ^M ^K'"Shend
Let us continue this discussion in chat.Cordiform
I
7

The %q format specifier comes close to your ideal output:

$ printf '%q' "abcd\refjh\bijk"
abcd\\refjh\\bijk

This outputs a string that is equivalent to your idea; for example, the shell treats '\r' and \\r exactly the same. Also,

$ printf '%q' $'\a\b\e\E\f\n\r\t\v\\\'\"'
$'\a\b\E\E\f\n\r\t\v\\\'"'

The output uses the ANSI quoting format to show a string containing actual unprintable characters.

To force ANSI quoting for strings that only contain printable characters, you can add an unprintable character to the end of the string, format it, then strip the added character.

$ var="My string"
$ printf -v var '%q' "$var"$'\n'   # Add a newline
$ [[ $var =~ \$\'(.*)\\n\' ]] && var="\$'${BASH_REMATCH[1]}'"
$ echo "$var"
Inferno answered 12/9, 2015 at 22:30 Comment(3)
brilliant, I like this a lot :)Shend
Is it possible to enforce the use of the ANSI-C Quoting syntax?Shend
I don't think there is an easy way, but see my update for a bit of a hack.Inferno

© 2022 - 2024 — McMap. All rights reserved.