Printing a string’s “canonical print-escaped form”

quotingzsh

I'm trying to write a function, I'll call it escape, that will behave like this:

% IFS=$' \t\n\000'
% escape FOO $IFS
FOO=$' \t\n\000'

In other words, escape takes two arguments, and then, taking the first one to be a variable name, it prints out a line a zsh source code in which a variable of that name is assigned a $''-quoted, "canonically print-escaped" string, such that, upon evaluating this line of source code, the variable named by the the first argument will have the second argument as its value. (I'm sure that was as clear as mud, so I'll give more examples of how escape is supposed to behave at the end of this post.)

Here's an incomplete implementation of the escape function:

escape () {
    local varname=$1
    local value="$2"
    print -n "$varname=\$'"
    # ???
    print "'"
}

The missing part (indicated by ???) is where the contents of $value are "canonically print-escaped". The qualifier "canonical" is necessary because there are many characters for which there are at least a couple of representations that print will recognize them as. For example, print knows \n also as \012 and as \C-J. In this case, \n is the canonical form. In general, the standard escape sequences \n, \r, \t, etc. are the canonical forms for their corresponding characters. The standard display form of printable ASCII characters (e.g. A, =, 9) are canonical. For the remaining characters, if there's a choice of representation, I'd pick the octal form as the canonical one (at least up to \177; I'm not sure of how $'' deals with higher codes), but this preference is not strong.

Of course, I'm not looking to see code to implement this functionality "from scratch", as it were. Rather, I'm hoping that a utility already exists to perform this translation from bytes to a print-escaped text representation.

Any pointers would be much appreciated!


Here are some more examples of escape in action (hypothetically):

% escape HELLO $( echo 'hello world' )
HELLO=$'hello world\n'
% escape SUBSEP $( perl -e 'print $;' )
SUBSEP=$'\034'
% abc=$'\141\012\142\012\143\012'
% print -n $abc
a
b
c
% escape ABC $abc
ABC=$'a\nb\nc\n'

Best Answer

I think ing for the q parameter expansion flag, specifically the qqqq variant.

FOO=${(qqqq)IFS}

So you can write your function this way (using the P flag to expand the parameter whose name is $2):

escape () {
  print -r -- "$1=${(Pqqqq)2}"
}
Related Question