[colug-432] Portable Visible Tabs in Shell Scripts

jep200404 at columbus.rr.com jep200404 at columbus.rr.com
Tue Aug 9 18:48:35 EDT 2011


How does one portably, visibly put a tab character in a shell 
script? 

On Mon, 8 Aug 2011 13:32:59 -0400, jep200404 at columbus.rr.com wrote:

> ... $'\t' ... It's time for me to RTFM. 

3.1.2.4 ANSI-C Quoting on pages 12-13 (labeled page 6-7) of: 

   http://www.gnu.org/software/bash/manual/bashref.pdf

Unfortunately, it seems to be a bashism and to not work in 
(plain) bourne shells. 
I've been trying to find a portable way of _visibly_ putting 
tab characters in shell scripts. 
The ways that dash and bash do it seem complementary. 
Even echo behaves differently in dash and bash. 
Below are screen scrapes of bash and dash use. 
I have not found a tidy solution. My goo script works (at 
least with bash versus dash), but is just disgusting. 

What are the better ways for portably, visibly putting a 
tab character in a shell script? 

--------------------------------------------------------------------------------

jep at jep-laptop:~$ ps
  PID TTY          TIME CMD
 5762 pts/6    00:00:00 bash
 6207 pts/6    00:00:00 ps
jep at jep-laptop:~$ echo -n '\t' | xxd -g 1 -u
0000000: 5C 74                                            \t
jep at jep-laptop:~$ echo -n -e '\t' | xxd -g 1 -u
0000000: 09                                               .
jep at jep-laptop:~$ echo -n "\t" | xxd -g 1 -u
0000000: 5C 74                                            \t
jep at jep-laptop:~$ echo -n -e "\t" | xxd -g 1 -u
0000000: 09                                               .
jep at jep-laptop:~$ cat foo.c
#include <stdlib.h>
#include <stdio.h>

int main(int argc,char *argv[])
{
   int i;
   unsigned char *s;

   for (i=0;i<argc;i++) {
      printf("#%d:",i);
      for (s=argv[i];*s!='\0';s++)
         printf(" %02X",*s);
      printf("\n");
   }

   exit(EXIT_SUCCESS);
}

jep at jep-laptop:~$ cc     foo.c   -o foo
jep at jep-laptop:~$ ./foo '\t'
#0: 2E 2F 66 6F 6F
#1: 5C 74
jep at jep-laptop:~$ ./foo "\t"
#0: 2E 2F 66 6F 6F
#1: 5C 74
jep at jep-laptop:~$ ./foo $'\t'
#0: 2E 2F 66 6F 6F
#1: 09
jep at jep-laptop:~$ ./foo $"\t"
#0: 2E 2F 66 6F 6F
#1: 5C 74
jep at jep-laptop:~$ cat goo
# note the absence of a shebang
echo "SHELL is $SHELL"
if echo "$SHELL" | grep -q '/bash$'; then
   echo bash way
   tab=$'\t'
   tab=`echo -e -n '\t'`
else
   echo bourne way
   tab=`echo -n '\t'`
fi

echo "hello${tab}world"

jep at jep-laptop:~$ ./goo
SHELL is /bin/bash
bash way
hello   world
jep at jep-laptop:~$ 

--------------------------------------------------------------------------------

$ ps
  PID TTY          TIME CMD
 4608 pts/5    00:00:00 dash
 6286 pts/5    00:00:00 ps
$ echo -n '\t' | xxd -g 1 -u
0000000: 09                                               .
$ echo -n -e '\t' | xxd -g 1 -u
0000000: 2D 65 20 09                                      -e .
$ echo -n "\t" | xxd -g 1 -u
0000000: 09                                               .
$ echo -n -e "\t" | xxd -g 1 -u
0000000: 2D 65 20 09                                      -e .
$ cat foo.c
#include <stdlib.h>
#include <stdio.h>

int main(int argc,char *argv[])
{
   int i;
   unsigned char *s;

   for (i=0;i<argc;i++) {
      printf("#%d:",i);
      for (s=argv[i];*s!='\0';s++)
         printf(" %02X",*s);
      printf("\n");
   }

   exit(EXIT_SUCCESS);
}

$ cc     foo.c   -o foo
$ ./foo '\t'
#0: 2E 2F 66 6F 6F
#1: 5C 74
$ ./foo "\t"
#0: 2E 2F 66 6F 6F
#1: 5C 74
$ ./foo $'\t'
#0: 2E 2F 66 6F 6F
#1: 24 5C 74
$ ./foo $"\t"
#0: 2E 2F 66 6F 6F
#1: 24 5C 74
$ cat goo
# note the absence of a shebang
echo "SHELL is $SHELL"
if echo "$SHELL" | grep -q '/bash$'; then
   echo bash way
   tab=$'\t'
   tab=`echo -e -n '\t'`
else
   echo bourne way
   tab=`echo -n '\t'`
fi

echo "hello${tab}world"

$ ./goo
SHELL is /bin/dash
bourne way
hello   world
$ 


More information about the colug-432 mailing list