11

I have a string in a shell/bash script. I want to print the string with all its "special characters" (eg. newlines, tabs, etc.) printed as literal escape sequences (eg. a newline is printed as \n, a tab is printed as \t, and so on).

(Not sure if I'm using the correct terminology; the example should hopefully clarify things.)

Example

The desired output of...

a="foo\t\tbar"
b="foo      bar"

print_escape_seq "$a"
print_escape_seq "$b"

...is:

foo\t\tbar
foo\t\tbar
  1. $a and $b are strings that were read in from a text file.
  2. There are two tab characters between foo and bar in the $b variable.

An attempt

This is what I've tried:

#!/bin/sh

print_escape_seq() {
  str=$(printf "%q\n" $1)
  str=${str/\/\//\/}
  echo $str
}

a="foo\t\tbar"
b="foo      bar"

print_escape_seq "$a"
print_escape_seq "$b"

The output is:

foo\t\tbar
foo bar

So, it doesn't work for $b.

Is there an entirely straightforward way to accomplish this that I've missed completely?

asymptote
  • 325
  • 1
  • 4
  • 13
  • are you looking to visualize the `\t` and `\n` chars, or would you take this output and then use it, expecting that `\t,\n` (etc), would work as usual? Good luck. – shellter Jan 18 '15 at 18:02
  • Yes, to visualise the `\t` and `\n` characters. The output is just for display on `stdout`. – asymptote Jan 18 '15 at 18:07
  • 1
    A good answer below, but maybe you should get comfortable reading the output of the shell debug/trace feature `set -vx; cmd1; cmd2 ... ; set +vx`. It will visualize your strings "for free". ;-) Good luck. – shellter Jan 18 '15 at 19:10

3 Answers3

7

Bash has a string quoting operation ${var@Q}

Here is some example code


bash_encode () {
  esc=${1@Q}
  echo "${esc:2:-1}" 
}

testval=$(printf "hello\t\tworld")
set | grep "^testval="
echo "The encoded value of testval is" $(bash_encode "$testval")

Here is the output

testval=$'hello\t\tworld'
The encoded value of testval is hello\t\tworld
Frobbit
  • 1,652
  • 17
  • 30
  • This works well for unknown special characters. For example I found a carriage return `\r`. – Martin Thøgersen Jun 23 '22 at 09:39
  • 1
    Btw, this does not work for length zero, due to the substring implementation that removes the surrounding `$'....'` part of the quoting. `testval=""; $(bash_encode "$testval")` return `substring expression < 0` – Martin Thøgersen Jun 23 '22 at 10:38
3

You will need to create a search and replace pattern for each binary value you wish to replace. Something like this:

#!/bin/bash

esc() {
    # space char after //
    v=${1// /\\s}   
    # tab character after //
    v=${v// /\\t}
    echo $v
}
esc "hello world"
esc "hello  world"

This outputs

hello\sworld
hello\tworld
user590028
  • 11,364
  • 3
  • 40
  • 57
0

I required something similar for file paths, and I realized that ls -1b does the work, but in the research I found this solution in stackoverflow which is closer to what you were requiring. Command to escape a string in bash

just compile it with gcc -o "escapify" escapify.c