Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Feb 1997 00:42:46 +0100 (CET)
From:      Arne Henrik Juul <arnej@imf.unit.no>
To:        FreeBSD-gnats-submit@freebsd.org
Cc:        arnej@imf.unit.no, jarle@runit.sintef.no, he@runit.sintef.no, tegge@idt.unit.no
Subject:   bin/2630: xargs does excessive and inconsistent argument splitting
Message-ID:  <199701312342.AAA07077@frida.imf.unit.no>
Resent-Message-ID: <199701312350.PAA19868@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         2630
>Category:       bin
>Synopsis:       xargs does excessive and inconsistent argument splitting
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jan 31 15:50:02 PST 1997
>Last-Modified:
>Originator:     Arne Henrik Juul
>Organization:
Norwegian University of Technology and Science
>Release:        FreeBSD 2.2-GAMMA i386
>Environment:

	This PR probably applies to most *BSD versions.

>Description:

	I was surprised when some command-line usage of xargs
	gave me trouble because it generated an empty argument.
	Further investigation shows that the BSD version of
	xargs (in net- and freebsd) splits the input in a very
	different way from everyone else, and it's also a bit
	inconsistent:  Leading blanks, or any double blanks
	will make xargs generate empty arguments, but a trailing
	blank will not.  I think it should be modified to be
	more like what everybody else does, and my expections were.
	At the very least the behaviour should be more consistent.

	The xargs specification is very loose and informal, but
	spec1170 says arguments should be 'separated by non-quoted
	blanks', which I read to support (or at least allow) my
	preferred behaviour.

	Even worse is that quoted empty strings will be treated
	the same way: A trailing "" string will be ignored.
>How-To-Repeat:

	Run these commands (preferrably on different xargs implementations).
cat > echoargs << 'eof'
#!/bin/sh
for x do echo "arg: '$x'"; done
eof
chmod +x echoargs
echo xargs is:
which xargs
echo test leading, embedded double, and trailing space
echo ' 1 2  3 ' | xargs ./echoargs
echo test leading, embedded, and trailing quoted empty string
echo '"" 2 "" 4 ""' | xargs ./echoargs

>Fix:
	
	This is a simple patch to make xargs behave like I think it
	should.  It is tested, but not very much.  It should be noted
	that this patch has an analogous effect on leading and double
	NULLs in the -0 case.  The -0 case can be argued both ways, I
	guess, but I haven't seen anything close to a spec for it, so
	I left it at this.
Index: xargs.c
===================================================================
RCS file: /usr/cvs/src/usr.bin/xargs/xargs.c,v
retrieving revision 1.3
diff -u -r1.3 xargs.c
--- xargs.c	1996/11/01 18:46:05	1.3
+++ xargs.c	1997/01/31 23:03:09
@@ -67,7 +67,7 @@
 {
 	register int ch;
 	register char *p, *bbp, *ebp, **bxp, **exp, **xp;
-	int cnt, indouble, insingle, nargs, nflag, nline, xflag;
+	int cnt, indouble, insingle, nargs, nflag, nline, xflag, wasquoted;
 	char **av, *argp, **ep = env;
 
 	/*
@@ -172,12 +172,6 @@
 			if (p == bbp)
 				exit(rval);
 
-			/* Nothing since end of last argument. */
-			if (argp == p) {
-				*xp = NULL;
-				run(av);
-				exit(rval);
-			}
 			goto arg1;
 		case ' ':
 		case '\t':
@@ -193,24 +187,23 @@
 			if (zflag)
 				goto addch;
 
-			/* Empty lines are skipped. */
-			if (argp == p)
-				continue;
-
 			/* Quotes do not escape newlines. */
 arg1:			if (insingle || indouble)
 				 err("unterminated quote");
-
-arg2:			*p = '\0';
-			*xp++ = argp;
+arg2:
+			/* Do not make empty args unless they are quoted */
+			if (argp != p || wasquoted) {
+				*p++ = '\0';
+				*xp++ = argp;
+			}
 
 			/*
 			 * If max'd out on args or buffer, or reached EOF,
 			 * run the command.  If xflag and max'd out on buffer
 			 * but not on args, object.
 			 */
-			if (xp == exp || p == ebp || ch == EOF) {
-				if (xflag && xp != exp && p == ebp)
+			if (xp == exp || p > ebp || ch == EOF) {
+				if (xflag && xp != exp && p > ebp)
 					err("insufficient space for arguments");
 				*xp = NULL;
 				run(av);
@@ -218,19 +211,21 @@
 					exit(rval);
 				p = bbp;
 				xp = bxp;
-			} else
-				++p;
+			}
 			argp = p;
+			wasquoted = 0;
 			break;
 		case '\'':
 			if (indouble || zflag)
 				goto addch;
 			insingle = !insingle;
+			wasquoted = 1;
 			break;
 		case '"':
 			if (insingle || zflag)
 				goto addch;
 			indouble = !indouble;
+			wasquoted = 1;
 			break;
 		case '\\':
 			if (zflag)
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199701312342.AAA07077>