Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Handling Double-quoted backslash



On Fri, 21 May 2010, Bart Schaefer wrote:

> On Fri, May 21, 2010 at 8:58 PM, EG Galano <eg.galano@xxxxxxxxx> wrote:
> > I'm not certain if this is a bug because many different shells 
> > handle the case differently. I started testing double-quoted 
> > backslashes with the newline character to see how the different 
> > shells handled the following commands. I'm no expert, but based on 
> > what I've learned about escaping charcters, I would think TCSH is 
> > the only one that handles it correctly. Is that not correct?
> 
> What  you've failed to account for is that shells also implement 
> "echo" differently, so the output is not determined solely by the 
> quoting.

Interestingly, the shells aren't consistent across the board regardless 
of how they implement 'echo'.  I don't think that makes one or the other 
"correct", per se (If anything, tcsh is in the minority, empirically).  
But I still thought it was worth sharing.

Printargs is just a stupid C program I whipped up to print out the 
arguments character-by-character with some [\r\n\t] handling. (gcc -Wall 
-o printargs{,.c})

zsh$ for l in bash zsh csh tcsh sh ksh fish psh dash mksh sash shish posh ; for s in 'a\nb' 'a\\nb' 'a\\\nb' ; printf "%s\t%s\t" $l $s && $l -c "printargs \"$s\"" 2>/dev/null
(The '2>/dev/null' kills a psh error under perl 5.12)

Results in the attached output.  ('sh' is a symlink to 'bash', and 'csh' 
is a symlink to 'tcsh')

So, with 1, 2, and 3 backslashes followed by an 'n':

bash, zsh, sh, ksh, fish, dash, mksh, sash, and posh keep 1, 1, and 2 
backslashes

csh, tcsh, and shish keep 1, 2, and 3 backslashes

Only psh interprets the '\n' as a newline, and adds: 0, 1, or 2 
preceding backslashes.

-- 
Best,
Ben
#include <stdio.h>
#include <ctype.h>

int main(int argc, char **argv) {
	int i, j;
	char c;
	for (i = 1; i < argc; i++) {
		if (i > 1) printf("\n");
		printf("argv[%d]:", i);
		for (j = 0; argv[i][j]; j++) {
			c = argv[i][j];
			printf(" ");
			if (!isspace(c)) printf("%c", c);
			else if (c == '\n') printf("(\\n)");
			else if (c == '\r') printf("(\\r)");
			else if (c == '\t') printf("(\\t)");
			else printf("(%02x)",c);
		}
		printf("\n");
	}
	return 0;
}
bash	a\nb	argv[1]: a \ n b
bash	a\\nb	argv[1]: a \ n b
bash	a\\\nb	argv[1]: a \ \ n b
zsh	a\nb	argv[1]: a \ n b
zsh	a\\nb	argv[1]: a \ n b
zsh	a\\\nb	argv[1]: a \ \ n b
csh	a\nb	argv[1]: a \ n b
csh	a\\nb	argv[1]: a \ \ n b
csh	a\\\nb	argv[1]: a \ \ \ n b
tcsh	a\nb	argv[1]: a \ n b
tcsh	a\\nb	argv[1]: a \ \ n b
tcsh	a\\\nb	argv[1]: a \ \ \ n b
sh	a\nb	argv[1]: a \ n b
sh	a\\nb	argv[1]: a \ n b
sh	a\\\nb	argv[1]: a \ \ n b
ksh	a\nb	argv[1]: a \ n b
ksh	a\\nb	argv[1]: a \ n b
ksh	a\\\nb	argv[1]: a \ \ n b
fish	a\nb	argv[1]: a \ n b
fish	a\\nb	argv[1]: a \ n b
fish	a\\\nb	argv[1]: a \ \ n b
psh	a\nb	argv[1]: a (\n) b
psh	a\\nb	argv[1]: a \ (\n) b
psh	a\\\nb	argv[1]: a \ (\n) b
dash	a\nb	argv[1]: a \ n b
dash	a\\nb	argv[1]: a \ n b
dash	a\\\nb	argv[1]: a \ \ n b
mksh	a\nb	argv[1]: a \ n b
mksh	a\\nb	argv[1]: a \ n b
mksh	a\\\nb	argv[1]: a \ \ n b
sash	a\nb	argv[1]: a \ n b
sash	a\\nb	argv[1]: a \ n b
sash	a\\\nb	argv[1]: a \ \ n b
shish	a\nb	argv[1]: a \ n b
shish	a\\nb	argv[1]: a \ \ n b
shish	a\\\nb	argv[1]: a \ \ \ n b
posh	a\nb	argv[1]: a \ n b
posh	a\\nb	argv[1]: a \ n b
posh	a\\\nb	argv[1]: a \ \ n b


Messages sorted by: Reverse Date, Date, Thread, Author