sending non-printable characters in expect script

Viewed 131

I found that when I use certain bytes as input to a program in an expect script, then there is an automatic conversion to multibytes when a byte is above 0x7f. For example the following line in the script:

spawn ./myprog [exec perl -e { print "\x7f\x80" }]

sends actually three instead of two bytes to myprog: 0x7f 0xc2 0x80

myprog is a simple test program that prints the input it gets:

int main(int argc, char** argv) {
   int i;
   for (i=0;i<strlen(argv[1]);i++) {
      printf("%x\n", (unsigned char)argv[1][i]);
}

I understand that 0x7f is the magic boundary to unicode-related encodings, but how can I just send a byte like 0x80 to my program? In the expect script I already tried conversions like [encoding convertto iso8859-1 [exec perl ...]] described in https://www.tcl.tk/doc/howto/i18n.html, but nothing works.

On the other hand, when I do the identical thing on the command line, e.g.:

./myprog `perl -e 'print "\x7f\x80"'`

I do get only two bytes - as expected (the differing {} compared to the expect script line is tcl's replacement of '').

How can I force the same behavior in an expect script?

1 Answers

After some more experimentation, I found that the only way to do that is to have the argument handover outside the expect logic, e.g.:

set input [binary format H* 7f80]
exec echo "$input" > input.dat
spawn sh -c "./myprog `cat input.dat`"

Note that using ${...} instead of backticks does not seem to work easily due to the special meaning of $ to expect.

Of course, having spawned a shell instead of the process directly is not the same thing but that does not matter for most of my use cases.

Related