Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'revealing' hidden/control 'codes' in strings in bash

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
like image 374
Thomasleveil Avatar asked Sep 12 '15 20:09

Thomasleveil


1 Answers

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"
like image 72
chepner Avatar answered Nov 15 '22 05:11

chepner