chet@kiwi.INS.CWRU.Edu (Chet Ramey) (07/01/89)
There are a few problems with the test builtin as released with bash 1.01. 1. I claim that test handles the unary negation operator (`!') incorrectly. Here is the test program I used: if [ ! -d /usr -a ! -d /etc ] ; then echo "Bogus" else echo "OK" fi I claim that "OK" should be echoed (on any Unix system). The following Bourne-style shells agree with me: 4.3 BSD /bin/sh SunOS 3.5 /bin/sh (s5r2-based) Ultrix 3.0 /bin/sh (4.2 BSD +) ksh version 06/03/86b Ultrix 3.0 /bin/sh5 (s5r2 shell) AIX 2.2.1 /bin/sh s5r2 /bin/sh s5r3.2 /bin/sh ash (Kenneth Almquist's shell) Vanilla Bash 1.01 echos "[: too many arguments". The problem is that "!" is recognized and handled in expr(), not in term(). The fix is simple. 2. The precendeces of -a and -o are switched. Fixes for this have already been posted by andy@csvax.caltech.edu (<8906240223.AA27273@csvax.caltech.edu>); I mention them only because they are also in the diffs. 3. I posted a fix for the test_syntax_error problem yesterday (6/28); that patch is in here. 4. The problem with -w, as reported by Peter Su (hugo@GRIGGS.DARTMOUTH.EDU), can be fixed by using access(). I changed -r to do so as well (-x already did). *** bash-1.01/test.c Fri Jun 23 00:43:13 1989 --- src-1.01/test.c Fri Jun 30 12:57:05 1989 *************** *** 33,39 **** #include <sys/stat.h> #include <sys/file.h> ! #ifndef X_OK #define X_OK 1 ! #endif #ifndef lint static char *rcsid="$Id: gtest.c,v 1.10 88/07/02 13:34:45 afb Exp Locker: afb $"; --- 33,42 ---- #include <sys/stat.h> #include <sys/file.h> ! #ifndef R_OK ! #define R_OK 4 ! #define W_OK 2 #define X_OK 1 ! #define F_OK 0 ! #endif /* R_OK */ #ifndef lint static char *rcsid="$Id: gtest.c,v 1.10 88/07/02 13:34:45 afb Exp Locker: afb $"; *************** *** 67,71 **** --- 70,78 ---- #endif /* STANDALONE */ + #ifndef SYSV int sys_v = 0; + #else + int sys_v = 1; + #endif static int pos; /* position in list */ *************** *** 73,76 **** --- 80,84 ---- static char **argv; /* the argument list */ + #ifndef SYSV static void test_syntax_error (pchFmt, args) *************** *** 84,87 **** --- 92,110 ---- } + #else + #include <varargs.h> + + static void + test_syntax_error(fmt, va) + char *fmt; + va_list va; + { + (void) fprintf(stderr,"%s: ", argv[0]); + (void) vfprintf(stderr, fmt, va); + (void) fflush(stderr); /* just in case */ + test_exit(SHELL_BOOLEAN(FALSE)); + } + #endif /* SYSV */ + test_io_error (name) char *name; *************** *** 195,198 **** --- 218,222 ---- * * term ::= + * '!' term * '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename * '-'('L'|'x') filename *************** *** 217,221 **** * expressions of the form '-l string'? */ ! auto int value, fd; if (pos >= argc) --- 241,245 ---- * expressions of the form '-l string'? */ ! auto int value; if (pos >= argc) *************** *** 222,225 **** --- 246,262 ---- beyond(); + if ('!' == argv[pos][0] && '\000' == argv[pos][1]) + { + value = FALSE; + + /* Deal with leading "not"s. */ + while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) + { + advance(1); + value ^= (TRUE); + } + return (value ^ term()); /* recursive descent */ + } + if ('(' == argv[pos][0] && '\000' == argv[pos][1]) { *************** *** 469,476 **** case 'r': /* file is readable? */ unary_advance (); ! fd = open (argv[pos - 1], O_RDONLY, 0600); ! if (value = fd != -1) ! close (fd); ! return (TRUE == value); --- 506,510 ---- case 'r': /* file is readable? */ unary_advance (); ! value = -1 != access (argv[pos - 1], R_OK); return (TRUE == value); *************** *** 477,487 **** case 'w': /* File is writeable? */ unary_advance (); ! fd = open (argv[pos - 1], O_WRONLY, 0600); ! if (value = fd != -1) ! close (fd); ! return (TRUE == value); ! case 'x': /* File is executable? */ unary_advance (); value = -1 != access (argv[pos - 1], X_OK); --- 511,518 ---- case 'w': /* File is writeable? */ unary_advance (); ! value = -1 != access (argv[pos - 1], W_OK); return (TRUE == value); ! case 'x': /* File is executable? Should we use executable_file() for this?*/ unary_advance (); value = -1 != access (argv[pos - 1], X_OK); *************** *** 600,609 **** /* ! * or: ! * or '-o' term * term */ static int ! or () { auto int value; --- 631,640 ---- /* ! * and: ! * and '-a' term * term */ static int ! and () { auto int value; *************** *** 610,616 **** value = term (); ! while (pos < argc && '-' == argv[pos][0] && 'o' == argv[pos][1] && '\000' == argv[pos][2]) { advance(0); ! value = TRUTH_OR (value, term ()); } return (TRUE == value); --- 641,647 ---- value = term (); ! while (pos < argc && '-' == argv[pos][0] && 'a' == argv[pos][1] && '\000' == argv[pos][2]) { advance(0); ! value = TRUTH_AND (value, term ()); } return (TRUE == value); *************** *** 618,634 **** /* ! * and: ! * and '-a' or ! * or */ static int ! and() { auto int value; ! value = or(); ! while (pos < argc && '-' == argv[pos][0] && 'a' == argv[pos][1] && '\000' == argv[pos][2]) { ! advance(1); ! value = TRUTH_AND (value, or()); } return (TRUE == value); --- 649,665 ---- /* ! * or: ! * or '-o' and ! * and */ static int ! or() { auto int value; ! value = and(); ! while (pos < argc && '-' == argv[pos][0] && 'o' == argv[pos][1] && '\000' == argv[pos][2]) { ! advance(0); ! value = TRUTH_OR (value, and()); } return (TRUE == value); *************** *** 637,642 **** /* * expr: ! * '!' expr ! * and */ int --- 668,672 ---- /* * expr: ! * or */ int *************** *** 643,660 **** expr() { - auto int value; - if (pos >= argc) beyond(); ! value = FALSE; ! ! /* Deal with leading "not"'s. */ ! while (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1]) { ! advance(1); ! ! /* This has to be rewritten to handle the TRUTH and FALSE stuff. */ ! value ^= (TRUE); ! } ! return value ^ and(); /* Same with this. */ } --- 673,679 ---- expr() { if (pos >= argc) beyond(); ! return FALSE ^ or(); /* Same with this. */ } *************** *** 687,690 **** --- 706,710 ---- test_exit (SHELL_BOOLEAN (FALSE)); if (']' != margv[margc][0] || '\000' != margv[margc][1]) { + argv = margv; /* for test_syntax_error */ test_syntax_error ("missing `]'\n"); } Chet Ramey "We are preparing to think about contemplating Network Services Group, CWRU preliminary work on plans to develop a chet@cwjcc.INS.CWRU.Edu schedule for producing the 10th Edition of the Unix Programmers Manual." -- Andrew Hume