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 $;' )
% abc=$'\141\012\142\012\143\012'
% print -n $abc
% escape ABC $abc

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


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}"
  • Thanks, but, sorry, I fail to see the relevance of your answer to my question. As I explicitly stated, I want the output of escape FOO $IFS (with $IFS set as in my original post) to be the string "FOO=$' \t\n\000'", verbatim, and not the string "FOO=${(qqqq)IFS}", nor the string "FOO=" followed by the string that ${(qqqq)IFS} gets expanded to (which is not easy to reproduce in a comment but is nothing remotely like the string "$' \t\n\000'"). – kjo Apr 24 '12 at 13:52
  • Sorry, there's a bug in the stackexchange software that causes a space to be lost in the first appearance of the substring "$' \t\n\000'" in my previous comment. – kjo Apr 24 '12 at 13:58
  • @kjo I told you the main feature you would use to implement the escape function, I didn't think implementing the function itself was part of the difficulty. But there you go, here's an escape function. – Gilles 'SO- stop being evil' Apr 24 '12 at 17:20
  • No, what I was missing was the -r flag to print, without which your original answer is not useful. Thanks. – kjo Apr 25 '12 at 2:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.