Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

In sh, is '[' a portable synonym for 'test'?

305 views
Skip to first unread message

Roy Smith

unread,
Sep 30, 1985, 11:41:54 AM9/30/85
to

On my 4.2bsd system, the following do the same thing in sh because
/bin/[ is a link to /bin/test. Test checks to see if it was called as "["
and in that case looks for the matching "]" at the end of the command.

if test -r wombat; then echo I can read wombat; fi
if [ -r wombat ]; then echo I can read wombat; fi

This is not documented anywhere in the 4.2 manual (that I can find)
but seems to be common practice. Is the "[]" form safe to use if you want
to make something portable? My Sys5 manual (January 1983) notes the two
forms but mentions that the second is not recognized on all systems. Does
anybody know on what systems it will fail?
--
Roy Smith <allegra!phri!roy>
System Administrator, Public Health Research Institute
455 First Avenue, New York, NY 10016

Guy Harris

unread,
Oct 12, 1985, 7:58:32 PM10/12/85
to
>
> On my 4.2bsd system, the following do the same thing in sh because
> /bin/[ is a link to /bin/test. ... Is the "[]" form safe to use if you want

> to make something portable? My Sys5 manual (January 1983) notes the two
> forms but mentions that the second is not recognized on all systems. Does
> anybody know on what systems it will fail?

V7 systems where /bin/[ isn't a link to /bin/test. Any V7 or post-V7 system
can be made to support "if [ <condition> ]" as equivalent to "if test
<condition>", but the S5 manual properly warns you that not all systems have
been made to support it. If you want to make something portable, and you
don't think you can convince every recipient of the program to make that
link, you're best off not using "[ ... ]".

GUy Harris

John Ruschmeyer

unread,
Oct 15, 1985, 10:26:02 AM10/15/85
to
>From: g...@sun.uucp (Guy Harris)
>Message-ID: <28...@sun.uucp>
>Organization: Sun Microsystems, Inc.

>
>V7 systems where /bin/[ isn't a link to /bin/test. Any V7 or post-V7 system
>can be made to support "if [ <condition> ]" as equivalent to "if test
><condition>", but the S5 manual properly warns you that not all systems have
>been made to support it. If you want to make something portable, and you
>don't think you can convince every recipient of the program to make that
>link, you're best off not using "[ ... ]".

Any good reason *NOT* to make the link?


--
Name: John Ruschmeyer
US Mail: Monmouth College, W. Long Branch, NJ 07764
Phone: (201) 222-6600 x366
UUCP: ...!vax135!petsd!moncol!john ...!princeton!moncol!john
...!pesnta!moncol!john

"It all started out as a mild curiousity in a junkyard...
and now it's turned out to be quite a spirit of adventure."

carl

unread,
Oct 15, 1985, 10:57:44 AM10/15/85
to
> >
> > On my 4.2bsd system, the following do the same thing in sh because
> > /bin/[ is a link to /bin/test. ... Is the "[]" form safe to use if you want
> > ....

>
> V7 systems where /bin/[ isn't a link to /bin/test. Any V7 or post-V7 system
> can be made to support "if [ <condition> ]" as equivalent to "if test
> .....
> GUy Harris

I have absolutely no arguments with Guy's message, but would like to point
out that the [ condition ] construct saves only one keystroke at the
expense of readability. E.g.:

if test -f "$1" <= 15 keystrokes + <CR>
vs.
if [ -f "$1" ] <= 14 keystrokes + <CR>

Which is more readable? Note that the spaces around [] are MANDATORY.

Carl Brandauer

Arthur David Olson

unread,
Oct 17, 1985, 10:55:40 AM10/17/85
to
> Any good reason *NOT* to make the link?

If you want your software to be portable to sites where the administrators
refuse to make the link (for *whatever* reason), don't make the link on your
own site.
--
UNIX is an AT&T Bell Laboratories trademark.
Sun is a Sun Microsystems trademark.
Sh is an American Librarians Association trademark.
--
UUCP: ..decvax!seismo!elsie!ado ARPA: elsie!a...@seismo.ARPA
DEC, VAX and Elsie are Digital Equipment and Borden trademarks

r...@mirror.uucp

unread,
Oct 18, 1985, 1:37:00 PM10/18/85
to

/* Written 10:57 am Oct 15, 1985 by carl@bdaemon in mirror:net.unix-wizar */
/* ---------- "Re: In sh, is '[' a portable synony" ---------- */

Carl Brandauer
/* End of text from mirror:net.unix-wizar */

Guy Harris

unread,
Oct 18, 1985, 3:52:12 PM10/18/85
to
> if test -f "$1" <= 15 keystrokes + <CR>
> vs.
> if [ -f "$1" ] <= 14 keystrokes + <CR>
>
> Which is more readable?

The latter, obviously; it reads more like a conditional statement rather
than a command. It may be *implemented* as a command (which, if the command
isn't builtin, slows it down - somebody who complained that "test" shouldn't
be built in was later seen using a "case" statement instead of an "if" and a
"test" in order to make it run faster), but that fact isn't relevant to
understanding what it *does*.

Good grief, do you think that people use the square bracket to save one
measly keystroke? That's not why it's there - it's there to improve the
readability of the statement.

Guy Harris

John Ruschmeyer

unread,
Oct 20, 1985, 11:39:18 AM10/20/85
to
>From: a...@elsie.UUCP (Arthur David Olson)
>Message-ID: <52...@elsie.UUCP>
>Organization: NIH-LEC, Bethesda, MD

>
>> Any good reason *NOT* to make the link?
>
>If you want your software to be portable to sites where the administrators
>refuse to make the link (for *whatever* reason), don't make the link on your
>own site.

Actually, that almost sounds like a good reason to make the link, but
never use it in your own software. Therefore you do have some compatability
with the Sys V and 4.2 programmers who use '[' instead of 'test'.

Now if there was a patch for the v7 'sh' to use '#' as a real comment....

pre...@ccvaxa.uucp

unread,
Oct 21, 1985, 1:06:00 PM10/21/85
to

> ... the [ condition ] construct saves only one keystroke at the

> expense of readability. E.g.:
>
> if test -f "$1" <= 15 keystrokes + <CR>
> vs.
> if [ -f "$1" ] <= 14 keystrokes + <CR>
>
> Which is more readable? Note that the spaces around [] are MANDATORY.
> /* Written 9:57 am Oct 15, 1985 by ca...@bdaemon.UUCP in
> ccvaxa:net.unix-wizards */
----------
Well, readability is very much in the eye of the beholder. I much
prefer the second form, which I gather you think is less readable.
The test part is bracketed. The syntax is closer to C. The word
"test" has been turned into a symbol, which is generally a good thing
[flamers please note and respect that "generally"].

Now, if you wanted to substitute words for the test names, I'd be
right with you. "-f" doesn't suggest anything to me...

--
scott preece
gould/csd - urbana
ihnp4!uiucdcs!ccvaxa!preece

Guy Harris

unread,
Oct 22, 1985, 3:40:58 AM10/22/85
to
> Now if there was a patch for the v7 'sh' to use '#' as a real comment....

If you don't have an S5 license, get the 4.xBSD 'sh' (assuming you have a
32V license); it's the V7 shell with '#' as a real comment (but it treats
any file whose first character is '#' as a C shell script). If you *do*
have an S5 license, use its shell instead - it's much improved (the S5R2
version even has Bourne's bastard Algol 68 expunged, finally, although it
still has the whacky method for storage allocation which causes plenty of
problems on machines which won't let user-mode code restart or continue
instructions).

Guy Harris

Ken Latham

unread,
Oct 23, 1985, 2:52:52 PM10/23/85
to
In reference to what I assume was the original question....

In sh, is ' [ ... ] ' a portable synonym for 'test ... '


The answer ( according to Bell Laboratories ) is NO!

See Unix system V Programmer's manual ( under 'test' )
( it states that SOME unix systems accept this notation )

However, both system V and system V.2 accept it! ( I double checked! )

I personally do not use it as it tends to mislead some people
into believing that it is an internal function of the shell.

Yours, ( well may not *yours* )

Ken Latham

( signature is in the primordial stages )

Doug Gwyn <gwyn>

unread,
Oct 24, 1985, 10:26:04 AM10/24/85
to
> ... If you *do*

> have an S5 license, use its shell instead - it's much improved (the S5R2
> version even has Bourne's bastard Algol 68 expunged, finally, although it
> still has the whacky method for storage allocation which causes plenty of
> problems on machines which won't let user-mode code restart or continue
> instructions).

This is real easy to fix.

/* @(#)blok.c 1.4 */
...
addblok(reqd)
...
bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd);
#ifdef mc68000 /* or if you just want to be sure */
/* at this point, bloktop may be beyond the break. I haven't been
* able to make the 68010 allow you to continue from a user bus
* trap after executing a signal handler that fixes up the bus
* trap, so we'll simply do a more intelligent thing and test
* the bloody thing before we use it. -- Wes Chalfant, FileNet Corp.
*/
if ((char *)&bloktop->word >= brkend)
fault(SIGSEGV);
#endif
bloktop->word = (struct blk *)(brkbegin + 1);

carl

unread,
Oct 24, 1985, 12:47:10 PM10/24/85
to
> > if test -f "$1" <= 15 keystrokes + <CR>
> > vs.
> > if [ -f "$1" ] <= 14 keystrokes + <CR>
> >
> > Which is more readable?
>
> The latter, obviously; it reads more like a conditional statement rather
> than a command.

Hogwash. The manual states

if *list* then *list* [ elif *list* then *list* ] ...

where *list* is defined as a sequence on one or more pipelines ,i.e
commands. *Test* is a command like any other, so why should it be treated
any differently?

> It may be *implemented* as a command (which, if the command
> isn't builtin, slows it down - somebody who complained that "test" shouldn't
> be built in was later seen using a "case" statement instead of an "if" and a
> "test" in order to make it run faster), but that fact isn't relevant to
> understanding what it *does*.

Agreed, irrelevant to the present discussion.

> Good grief, do you think that people use the square bracket to save one
> measly keystroke? That's not why it's there - it's there to improve the
> readability of the statement.
>
> Guy Harris

Yes, but only by people who want to obscure the fact that "if tests the
value returned by the last simple command following it" (S. R. Bourne,
The UNIX System, page 58).

Carl Brandauer

Dave Abbajay

unread,
Oct 25, 1985, 3:36:49 PM10/25/85
to

I also have no REAL arguments against Guy's comments save one. '/bin/test'
is a *program* and '[]' is intrepreted by the shell in all Sys III (and
greater) Bourne shells. This could have significant impact on shell script
performance, obviously, especially where loops are concerned. I was not
aware that a link between /bin/test and /bin/[ would make the '[]'
construct work in shells where '[]' was not supported! In my way of thinking,
this makes '[]' even MORE desirable for portability reasons (if the
link can be made on the target machine) as then you only pay the additional
overhead of the 'execs' of "test\[" on those machines where the shell doesn't
support '[]'.

And saving a keystroke for every test condition can be a desirable thing to
do, especially with some of the shell scripts I've written :-).


--
Dave Abbajay
Senior Technical Staff
ORACLE Corporation
(415)854-7350 hplabs!oracle!abbajay

BALDWIN

unread,
Oct 25, 1985, 11:38:01 PM10/25/85
to
> > > if test -f "$1" <= 15 keystrokes + <CR>
> > > vs.
> > > if [ -f "$1" ] <= 14 keystrokes + <CR>
> > >
> > > Which is more readable?
> >
> > The latter, obviously; it reads more like a conditional statement rather
> > than a command.
>
> Hogwash. The manual states
>
> if *list* then *list* [ elif *list* then *list* ] ...
>
> where *list* is defined as a sequence on one or more pipelines ,i.e
> commands. *Test* is a command like any other, so why should it be treated
> any differently?

Who cares WHAT [ or test really are? I *like* if statements to look like if
statement, thank you.
if [ $x = 3 ]
is more pleasing AND READABLE to me than
if test $x = 3

> > Good grief, do you think that people use the square bracket to save one
> > measly keystroke? That's not why it's there - it's there to improve the
> > readability of the statement.
> >
> > Guy Harris
>
> Yes, but only by people who want to obscure the fact that "if tests the
> value returned by the last simple command following it" (S. R. Bourne,
> The UNIX System, page 58).

Oh, bushwah! I don't want to obscure what the if stmt does, I want to
make it LESS obscure. If you ask me, "if test expr" is obscuring the
fact that this is a simple conditional, whereas "if [ expr ]" is obvious.

Speaking of test, is anyone else out there annoyed that there really
isn't a good way to deal with strings? Instead of nice and simple
[ "$x" = foo ] you have to say [ "X$x" = Xfoo ] which is kinda ugly.
Also, [ -n "$x" ] is right out (what if x is "="?), along with -z.
Expr has the same problem with "expr string : regexp". Bleah!
--
Michael Baldwin
{at&t}!whuxl!mike

Guy Harris

unread,
Oct 26, 1985, 8:23:44 PM10/26/85
to
> This is real easy to fix.

I know - I had to fix it here; I did so by doing the "setbrk" directly
instead of faking a SIGSEGV. (The code in question - added to the shell -
was allocating some BMF structures, and I didn't feel like having the shell
keep bumping its data space up until it got big enough).

Your line numbers may differ. This is for the S5R2 shell. It's probably
similar for others.

*** /tmp/da6483 Sat Oct 26 15:17:15 1985
--- blok.c Thu Oct 10 18:20:49 1985
***************
*** 87,92
reqd &= ~(brkincr - 1);
blokp = bloktop;


bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd);

bloktop->word = (struct blk *)(brkbegin + 1);

{
register char *stakadr = (char *)(bloktop + 2);

--- 87,95 -----
reqd &= ~(brkincr - 1);
blokp = bloktop;


bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd);

+ reqd = (char *)(&bloktop->word) - brkend;
+ if (reqd > 0 && setbrk(reqd) == (char *)-1)
+ error(nospace);


bloktop->word = (struct blk *)(brkbegin + 1);

{
register char *stakadr = (char *)(bloktop + 2);

The reason why this causes problems on 68010s is not that you can't continue
from an instruction. The problem is that you can't do so *from user mode*
without kernel hacks. In order to continue the instruction, the "stack
puke" (as Henry Spencer described it) must be on the stack when the RTE is
done. The RTE must be done from the kernel, since it's privileged. In some
UNIXes, returning from a signal doesn't involve the kernel (you can do an
RTR to reload the condition codes) - you're out of luck there. In others
(like 4.2BSD, which has to reenable the signal in question) returning from a
signal requires you to pass through the kernel. However, the bus error
frame isn't likely to be on the kernel stack anymore. You'd have to
squirrel it away somewhere - somewhere inaccessible to the user, because I
don't think Motorola tells you 1) that it won't kill the system if you RTE
with arbitrary bits or 2) how to make sure that a bus error frame is safe.
Sun UNIX doesn't do this, and other 68010 UNIXes may not either.

Guy Harris

Guy Harris

unread,
Oct 26, 1985, 8:35:25 PM10/26/85
to
> '/bin/test' is a *program* and '[]' is intrepreted by the shell in all
> Sys III (and greater) Bourne shells.

Yes, but "test" (as opposed to "/bin/test") is interpreted by the shell in
all Sys III (and greater) Bourne shells! Yes, this means

1) you can't run a program in your current directory named "test" by
typing "test" - you have to type "./test"

and

2) even if "/bin" is the first directory in your PATH containing
a program called "test", "/bin/test" and "test" do different
things.

This may seem strange, but since it's true its strangeness is irrelevant to
the discussion.

Guy Harris

Doug Gwyn <gwyn>

unread,
Oct 27, 1985, 2:32:41 AM10/27/85
to
If your Bourne shell has "[" built-in, it will probably have
"test" built-in, too, so the efficiency argument is moot.

I would like to again make the point that NOTHING anyone does is
going to guarantee that ANY particular code (shell script or not)
will necessarily work on all implementations of UNIX. The approach
I prefer is to provide as close to the same common environment as
possible everywhere; this reduces porting problems substantially.

Brandon Allbery

unread,
Oct 27, 1985, 6:53:34 PM10/27/85
to
Expires:

Quoted from <2000031@ccvaxa> ["Re: In sh, is '[' a portable synony"], by pre...@ccvaxa.UUCP...
+---------------


| > if test -f "$1" <= 15 keystrokes + <CR>
| > vs.
| > if [ -f "$1" ] <= 14 keystrokes + <CR>
| >
| > Which is more readable? Note that the spaces around [] are MANDATORY.
| > /* Written 9:57 am Oct 15, 1985 by ca...@bdaemon.UUCP in
| > ccvaxa:net.unix-wizards */
| ----------
| Well, readability is very much in the eye of the beholder. I much
| prefer the second form, which I gather you think is less readable.

+---------------

In general, when I am using the math/binary ops I use [, but when I want to
use the file predicates I use test. Thus:

if [ $expr -gt 5 ]; then

but

if test -s /tmp/toMl$$; then

--
``Youth, you are guilty of muddy thinking.''

Mentor

ncoast!all...@Case.CSNet (ncoast!allbery%Case....@CSNet-Relay.ARPA)
..decvax!cwruecmp!ncoast!bsa -- maybe ..genrad!mit-eddie!futura!ncoast!allbery
6615 Center St., Mentor, OH 44060 (I moved) --Phone: +01 216 974 9210
CIS 74106,1032 -- MCI MAIL BALLBERY (WARNING: I am only a part-time denizen...)
ncoast is dead, long live ncoast!

Doug Gwyn <gwyn>

unread,
Oct 28, 1985, 2:22:06 PM10/28/85
to
It appears that Guy's fix will make SIGSEGV available for general use
rather than reserved to the shell internals. That would be nice.

Larry West

unread,
Oct 29, 1985, 5:43:52 PM10/29/85
to
>
> if test -f "$1" <= 15 keystrokes + <CR>
> vs.
> if [ -f "$1" ] <= 14 keystrokes + <CR>
>
> Which is more readable? Note that the spaces around [] are MANDATORY.

I don't really know which is more readable (though I wonder
why the author was confusing this with the number of keystrokes
-- redundancy often aids readability, and in particular the
spaces around [] are helpful).

However, I would like to point out that users have a habit
of naming programs "test", and of having "/bin" occur late
in their paths. This tends to cause confusion because the
problem (as usual) doesn't come up until that brief "test"
program has been forgotten.

So, my suggestion is to always use "/bin/test" instead
of simply "test", or else use "[ ]". I know, fixing the
the particular pathname of a program is a bad idea, but this
seems a fairly safe case (unless you plan to provide an
improved user interface to "test":-).
--

Larry West (USA+619-)452-6771
Institute for Cognitive Science non-business hours: 452-2256
UC San Diego (mailcode C-015)
La Jolla, CA 92093 U.S.A.

ARPA: <we...@nprdc.ARPA> or <we...@ucsd.ARPA>
UUCP: {ucbvax,sdcrdcf,decvax,ihnp4}!sdcsvax!sdcsla!west
or {sun,mplvax,gti,ihnss,whuxlb,ulysses}!sdcsla!west

Ed Reeder

unread,
Nov 4, 1985, 1:30:00 PM11/4/85
to
Another reason '[' is used instead of test is it prevents problems
when the user has a file named 'test' in his current directory AND
his search path searches his current directory before /bin (for
systems that don't have test built in to the shell).

While everyone should reset PATH to avoid the problem, we don't
(as evidenced by net.sources).

Ed Reeder
Intel Corporation
Phoenix

Guy Harris

unread,
Nov 9, 1985, 3:16:00 AM11/9/85
to
> It appears that Guy's fix will make SIGSEGV available for general use
> rather than reserved to the shell internals. That would be nice.

Don't count your blessings until they've hatched, or something like that.
It doesn't make it available for general use, trust me. You also have to
catch *all* the places where Bourne uses SIGSEGV to catch attempts to use
unallocated portions of the "stack" (temporary string space and the like is
allocated on a "stack" which consists mostly of the growing end of the data
space, although it's intermixed with blocks from the heap). I got bit by
that a couple of days ago, and found *every* place where the "pushstak"
macro was used and added a test before it; if the place where the character
is to be "pushed" doesn't exist, it grows the data space. I don't claim to
have caught every place; I want to beat on it a while, and then build a
version of the shell which *does* make SIGSEGV available for "general" use
(i.e., the shell will drop core on a SIGSEGV like it's supposed to) and try
it for a while.

It was a clever idea, my hat's off to Bourne, but I still want to get the
vanity plate SIGSEGV for him and weld it to his car, if he's got one.

Guy Harris

Joseph S. D. Yao

unread,
Nov 9, 1985, 11:38:46 AM11/9/85
to
In article <1...@oracle.UUCP> abb...@oracle.UUCP (Dave Abbajay) writes:
>I also have no REAL arguments against Guy's comments save one. '/bin/test'
>is a *program* and '[]' is intrepreted by the shell in all Sys III (and
>greater) Bourne shells.

[Disclaimer:] I don't have the sV Bourne shell code or the Korn
shell code in front of me; however, I don't remember '[' being
treated as a special command. I do know that 'test' is linked
to '['. It does not seem logical to have it both ways, especially
when one can be changed without changing the other. (Did I s a y
that everything progrmmers do is logical?)

References: VAX-11/780 running s5r1v1, s5r1v2, s5r2v1, s5r2v2.

(Note: PLEASE reference the system you're talking about. I don't
know whether D.A. was talking about vaxen (prob'ly) or one of the
myriad 680X0 systems, or 3B's, or what.)
--

Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}

Tim Radzykewycz

unread,
Nov 13, 1985, 11:22:43 AM11/13/85
to
In article <6...@hadron.UUCP> js...@hadron.UUCP (Joseph S. D. Yao) writes:
>In article <1...@oracle.UUCP> abb...@oracle.UUCP (Dave Abbajay) writes:
>>I also have no REAL arguments against Guy's comments save one. '/bin/test'
>>is a *program* and '[]' is intrepreted by the shell in all Sys III (and
>>greater) Bourne shells.
>
>[Disclaimer:] I don't have the sV Bourne shell code or the Korn
>shell code in front of me; however, I don't remember '[' being
>treated as a special command. I do know that 'test' is linked
>to '['.
>References: VAX-11/780 running s5r1v1, s5r1v2, s5r2v1, s5r2v2.

A while back, the sysadm (somewhat junior) of a site I was working
on found the file '/bin/[', and thinking it was a junk file created
when something went wrong, he got rid of it. All kinds of shell
scripts broke. This is pretty conclusive evidence that '[' is
*not* treated specially, at least on the 4.1 (vax) system this
was on.

BTW: the sysadm was *me*.
--
Tim (radzy) Radzykewycz, The Incredible Radical Cabbage
calma!ra...@ucbvax.ARPA
{ucbvax,sun,csd-gould}!calma!radzy

Ian F. Darwin

unread,
Dec 8, 1985, 4:55:16 PM12/8/85
to
In article <10...@sdcsla.UUCP> we...@sdcsla.UUCP (Larry West) writes:
>However, I would like to point out that users have a habit
>of naming programs "test", and of having "/bin" occur late
>in their paths. This tends to cause confusion because the
>problem (as usual) doesn't come up until that brief "test"
>program has been forgotten.
>
>So, my suggestion is to always use "/bin/test" instead
>of simply "test", or else use "[ ]". I know, fixing
>the particular pathname of a program is a bad idea, but this
>seems a fairly safe case (unless you plan to provide an
>improved user interface to "test":-).

No, no, no. Do not use absolute paths for test, mv, cp, or
anything else. Least of all in shell files.

Sure, once in a while a new user will make a program called `test'
and get confused. Some people even do it twice (I did). Most
people don't do it a third time.

Note that the problem only comes up if you have your `test'
program in your $HOME/bin (what you call your private bin directory)
OR if you are in the same directory where you made that long-forgotten
test program.

On the other hand, if you post even a single shell file with /bin/test
in it, your `error' will be repeated hundreds of times all over the world.
Why is it an error? I call it an error because it violates the
portability principle: UNIX uses the PATH environment variable
to find programs, rather than making the user specify full path names
for programs. This allows you to write your own. Why would anybody
want to mv test out of /bin? Well, what if somebody decides that
test is used so often that it belongs in the shell? Then you have
to keep two versions of test around -- a fast one inside the shell,
and a slow one for `erroneuos' shell files. Oh, you say that they already
did this in some release of System V? My, what a surprise.

I'm equally against the practice of putting /bin/rm, /bin/mv, etc
into shell files. Please use rm, mv, etc, rather than the full paths.
You don't know what might motivate me to have my own version of rm
(indeed, you probably don't want to know what motivates me :=!). Please use
the facilities that UNIX provides. Don't negate UNIX's wonderful generality
for the benefit of a few nanoseconds.

Ian Darwin
Toronto, Canada

Ron Wessels

unread,
Dec 9, 1985, 2:51:45 AM12/9/85
to
>From: i...@utcs.uucp
>Subject: Please do NOT use "/bin/test" as a command name
>Message-ID: <10...@utcs.uucp>

>
> No, no, no. Do not use absolute paths for test, mv, cp, or
> anything else. Least of all in shell files. ...
> ....it violates the
> portability principle: UNIX uses the PATH environment variable
> to find programs, rather than making the user specify full path names
> for programs. This allows you to write your own. ...
> ...

> You don't know what might motivate me to have my own version of rm
> ...

There's one small problem with that, Ian. People writing "portable"
shell files don't know the behaviour of *your* rm (for example). What
flags does it take? Does it support the same ones as /bin/rm? Does it
behave similarly? I know some people that move rm'ed files to their own
private pergatory, in case they ever want them back. Others have their
own "rm" that does a "/bin/rm -i". A lot of otherwise-correct shell
files will behave very strangely if they use this non-standard version.
In short, /bin/rm is the only one that the shell-file writer can trust
to execute as s/he expects, and so should be the one invoked.
--
Ron Wessels Computer Systems Research Institute University of Toronto
UUCP: {decvax,floyd,ihnp4,linus,utzoo,uw-beaver}!utcsri!ron
CSNET: ron@Toronto
ARPA: ron%Toronto@CSNet-Relay

Dave Legg

unread,
Dec 9, 1985, 9:25:57 AM12/9/85
to
> = Ian Darwin
>> = Larry West

In article <10...@utcs.uucp> i...@utcs.UUCP (Ian F. Darwin) writes:
>In article <10...@sdcsla.UUCP> we...@sdcsla.UUCP (Larry West) writes:
>>However, I would like to point out that users have a habit
>>of naming programs "test", and of having "/bin" occur late

>>in their paths. ...


>>
>>So, my suggestion is to always use "/bin/test" instead

>>of simply "test", or else use "[ ]". ...


>
>No, no, no. Do not use absolute paths for test, mv, cp, or
>anything else. Least of all in shell files.
>

I can see both sides of this, I have run up against a user reporting a
strange failure of a shell script that is installed for general use, and
which usually works with no problem. The problem is that the user that
finds such a problem is usually new and inexperienced, and it can take
signifigant amounts of time to find that the whole problem is simply a
name collision.

One point not mentioned in the article I saw was that of the collision
with a users program that had undesirable side effects. For example,
if a user writes a program to delete files, and calls it some common system
program name, then runs a script (which he might not even know is a script)
which calls on that name.

I have a suggestion.
Set a shell variable to the absolute path of the program, i.e.
TEST=/bin/test (or equivelent for other shells)
and use $TEST in the shell program. This isolates the dependencies at
the top of the script, making for easy changes. As for portability,
if the changes are obvious and at the top, then any body getting a script
from the net should be able to see what is necessary.
Anybody recieving a script will normally at least scan it briefly to see
what it does, especially if it fails.

Although I can see that it is generally
desirable to be as portable as possible, in shell scripts, I now normally
fully qualify all proram names via the above convention. This is purely
on the basis of experience with problems caused by unqualified program
names in scripts.

--
Dave Legg, DCIEM, Toronto, Ont. Canada. (416) 635-2065
{linus,ihnp4,uw-beaver,floyd}!utcsri!dciem!davel
{allegra,ihnp4,linus,decvax}!utzoo!dciem!davel

Geoff Collyer

unread,
Dec 9, 1985, 3:39:13 PM12/9/85
to
In article <17...@dciem.UUCP>, Dave Legg writes about Ian Darwin's
suggestion that absolute path names not be burned in to shell scripts,
and suggests that they be burned in at the top, in definitions like
TEST=/bin/test. (This is a particularly bad example since, as Ian
pointed out, test is a shell built-in in modern shells, but /bin/test is
not.)

Ian didn't mention our standard practice here: set PATH at the top of
the shell script (e.g. PATH=/bin:/usr/bin; export PATH). This is really
essential since otherwise an oddball PATH may result in a shell file
executing commands with the same name as standard commands but with
completely different effects. The author of a shell file usually
intends that the standard commands be used.

Yes, it does mean that your private versions of the standard commands
will not be found in shell files which set PATH to the standard
directories, but this is often just as well. Rather than rehash this
whole issue, I refer the interested reader to The UNIX* Programming
Environment by Brian Kernighan and Rob Pike, in which I believe this
topic is fairly thoroughly covered.

___
* According to p. 8 of the November 1985 issue of "$ echo", an
overpriced AT&T Marketing & Legal rag, I must, being a foreigner, utter
the magic mantra "Trademark of AT&T in the USA and other countries."

Ilya Goldberg

unread,
Dec 10, 1985, 12:42:19 AM12/10/85
to
In article <10...@utcs.uucp> i...@utcs.UUCP (Ian F. Darwin) writes:
>I'm equally against the practice of putting /bin/rm, /bin/mv, etc
>into shell files. Please use rm, mv, etc, rather than the full paths.
>You don't know what might motivate me to have my own version of rm
>(indeed, you probably don't want to know what motivates me :=!). Please use
>the facilities that UNIX provides. Don't negate UNIX's wonderful generality
>for the benefit of a few nanoseconds.
>
>Ian Darwin
>Toronto, Canada

Ian, no one is trying to save cpu time by doing what they are doing.
Just think of what would happen if the user doesn't have the right things
in his/her path variable or no path at all!

Also, I would love to try to break into a system kept secure by your
shell scripts which do not contain absolute path names. I would do exactly
what you suggest - substitute my own versions of rm, mv, etc so that when
a set-u-id root shell script tries to execute one of those, UNIX will take
the version in my directory. My version will perform whatever I want it to.
including things you might not want me to.

So, when writing programs/shell scripts which call other programs
do include full path names, preferrably in a place where they are easily
found and can be easily modified (e.g. ".h" files).

Ilya (...!ucbvax!ilya)

Chris Torek

unread,
Dec 10, 1985, 9:39:39 AM12/10/85
to
[PATH=/foo:/bar:/baz; export PATH]

In article <11...@ucbvax.BERKELEY.EDU> cc...@ucbcory.BERKELEY.EDU
(Ilya Goldberg) writes:

> no one is trying to save cpu time by doing what they are doing.
> Just think of what would happen if the user doesn't have the right
> things in his/her path variable or no path at all!

Then nothing works at all, so why worry about that case?

> Also, I would love to try to break into a system kept secure by
> your shell scripts which do not contain absolute path names.

Who uses setuid shell scripts? (Actually, I have on one machine
a shell script that is run privileged by a separate setuid C program,
which verifies the user first; and the script is relatively careful.)

> I would do exactly what you suggest - substitute my own versions of
> rm, mv, etc so that when a set-u-id root shell script tries to
> execute one of those, UNIX will take the version in my directory.

Putting in full path names is not the solution---suppose I change $IFS?

> So, when writing programs/shell scripts which call other programs
> do include full path names, preferrably in a place where they are
> easily found and can be easily modified (e.g. ".h" files).

Include *paths*, not full path *names*. There is a difference. See
`man execvp' and `man execlp'.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP: seismo!umcp-cs!chris
CSNet: chris@umcp-cs ARPA: ch...@mimsy.umd.edu

Doug Gwyn <gwyn>

unread,
Dec 10, 1985, 10:31:09 AM12/10/85
to
I have to disagree with Ian on this one.
Because you never know what kind of weird $PATH
people will be using, it is essential when
writing shell scripts for use by others to
FORCE the correct commands to be used in
your shell script, in order to guarantee
that the script does what you intended.
The simplest way to do this is to just set
PATH=whatever at the front of the script.
Besides being less trouble than using absolute
pathnames, this also handles problems like:
Is "sort" in /bin or /usr/bin (or /usr/5bin)?

The internals of a utility are subject to change.
You can't even reasonably make the user
responsible for looking inside utilities to see
whether they will work in conjunction with his
$PATH. As far as a user should be concerned, a
utility should be a "black box" that does its job
reliably and without fuss. If you're going to
make a utility reliable, its internal operation
should be protected against environmental factors
except when they are a deliberate part of the
interface. If someone has his own "rm" command
(some of our users do), how do you know that it
is suitable for use in your script to remove a
link? The answer is, you don't.

Martin Stanley

unread,
Dec 10, 1985, 10:59:54 AM12/10/85
to

And just to add fuel to the fire:

What about personal aliases conflicting with csh script commands. For
example, many people around here alias rm to rm -i. This would break
many csh scripts. The PATH solution given in geoff's article would not
solve this problem.

Of course, a *very* conscientious programmer could unalias every
potentially conflicting name he uses in a script. :-)
--

Martin Stanley
Department of Computer Science
University of Toronto
Toronto, ON
M5S 1A4

USENET: {decvax,ihnp4,linus,uw-beaver}!utcsri!utai!ms!mts
CSNET: mts@toronto
ARPANET: mts.toronto@csnet-rela

Rudy Bazelmans x72609 ms 1989

unread,
Dec 11, 1985, 8:15:11 AM12/11/85
to
> So, when writing programs/shell scripts which call other programs
> do include full path names, preferrably in a place where they are easily
> found and can be easily modified (e.g. ".h" files).
>
> Ilya (...!ucbvax!ilya)

Users should NOT use full directory names in their scripts/programs UNLESS:

1) They specifically do not want the local version of a program.
2) They are writing setuid scripts (actually, this would be alright too if
the script changed the path variable).

If users use fullly qualified pathnames for programs, then administrators of
systems would have to replace the standard programs with the new ones rather
than allow both to be available.

Gregory M. Paris

unread,
Dec 10, 1985, 8:42:49 PM12/10/85
to
> No, no, no. Do not use absolute paths for test, mv, cp, or
> anything else. Least of all in shell files.
>
> Sure, once in a while a new user will make a program called `test'
> and get confused. Some people even do it twice (I did). Most
> people don't do it a third time.

As you mentioned, this kind of problem crops up not only with
"test" but with many of the oft-used UNIX utilities. For those of
us that support a user community of hundreds, even one or two "custom"
utility problems per user can become quite a time consuming hassle.
Just about any shell script can be broken with custom utilities, and
I certainly don't expect every user to have the savvy to figure out
which ones his/her new "rm" command is going to break (try rm -i -f).

There's more than a speed advantage to including full pathnames,
and only very minor portability problems associated with the practice.
I'm not saying that you *must* or even *should* include full pathnames,
but I disagree completely with your saying *never*!

As a compromise, how about setting PATH at the beginning of the script?
--

++---------------------------------------------------------------------------++
|| Greg Paris {allegra,linus,raybed2,ccice5,brunix}!rayssd!gmp ||
++---------------------------------------------------------------------------++

S|ren K. Lundsgaard

unread,
Dec 11, 1985, 5:48:03 AM12/11/85
to
This is all very easily solved for both csh and shell scripts.

merely set the correct path for all the commands that you have
used, or will possibly use in the shell script.

for example

#!/bin/sh
# set our explicit path
PATH="/bin:/usr/bin:/usr/ucb:$PATH"

for i in p px ph tr
do
if test -d $i
then
dirnames="$dirnames $i"
fi
done
.
.
.

Notice that I carried along the old path for good measure, in
case the script runs a shell or something, but I know that I will
get /bin/test, instead of ./test, or any other garbage that is
sitting in the path.

Another option is to save the old path in another environment variable,
and then set it back when you are ready to go on in the old
environment.

----
Um Yah Yah.
skl.

j...@teddy.uucp

unread,
Dec 12, 1985, 9:02:15 AM12/12/85
to
>What about personal aliases conflicting with csh script commands. For
>example, many people around here alias rm to rm -i. This would break
>many csh scripts. The PATH solution given in geoff's article would not
>solve this problem.

Assuming you are talking about csh aliases, this does not come up in
"sh" scripts (which was what the discussion was about). If you are
writing csh scripts, then I hope your kernel also supports the "#! xxx"
shell hack, or else the csh script startup times may be prohibatively
long. If your kernel supports this, then use "#! /bin/csh -f" to avoid
loading the user's .cshrc.

>Of course, a *very* conscientious programmer could unalias every
>potentially conflicting name he uses in a script. :-)

How about "unalias *"?

Henry Spencer

unread,
Dec 12, 1985, 4:43:37 PM12/12/85
to
> In short, /bin/rm is the only one that the shell-file writer can trust
> to execute as s/he expects, and so should be the one invoked.

No, the one the shell-file writer can trust is PATH=/bin:/usr/bin rm,
not /bin/rm. /bin/rm may not even exist (although it would be surprising).

Henry Spencer

unread,
Dec 12, 1985, 4:45:31 PM12/12/85
to
> What about personal aliases conflicting with csh script commands...

>
> Of course, a *very* conscientious programmer could unalias every
> potentially conflicting name he uses in a script. :-)

A conscientious programmer would never use csh to write scripts.

Henry Spencer

unread,
Dec 12, 1985, 4:47:39 PM12/12/85
to
> Also, I would love to try to break into a system kept secure by your
> shell scripts which do not contain absolute path names. I would do exactly
> what you suggest - substitute my own versions of rm, mv, etc...

Wouldn't help, since all those shell scripts start with the magic line:

PATH=/bin:/usr/bin ; export PATH

which solves the problem without requiring hardwired path names everywhere.
Also, it solves the problem for everything invoked by the shell script,
rather than just for the shell script itself.

Henry Spencer

unread,
Dec 12, 1985, 4:49:39 PM12/12/85
to
> As a compromise, how about setting PATH at the beginning of the script?

This is not a compromise, it is the correct and complete solution. Don't
forget to do "export PATH".

Tim Bray

unread,
Dec 12, 1985, 7:53:13 PM12/12/85
to
I am NOT a unix-wizard. But it seems elementary to me that all shell scripts
should be as follows:

#!/bin/sh
PATH=/bin:/usr/bin:/usr/ucb # 'n maybe some more
if test bletch ....
mv foo
rm bar
etc..

That way you can't get bitten by (maybe intentional) name duplication, you
will preserve the flexibility of path usage, and everything is hunky dory.
This assumes that you can trust the contents of /bin:/usr/bin:/usr/ucb.
If you want to use nonstandard commands as a privileged person, you should
#$&*)$ well have them in a protected place - we use /opr.

We had a secretary who created a little script called 'test' (dunno why) that
printed out some guy's performance appraisal on her screen, and it turns
out there were a FEW system scripts promiscuously using 'test' without
protecting their paths - she was pretty upset for a while.

Bill.Stewart.4K435.x0705

unread,
Dec 14, 1985, 11:06:48 PM12/14/85
to

Henry and Ian are usually right :-), but ......
Actually, it has the potential for BREAKING almost everything invoked
by the shell script, though not the shell script itself! If you do

PATH=/bin:/usr/bin:$PATH: ; export PATH

(perhaps with /usr/ucb/bin or /usr/lbin wedged in there) then the
script can call other scripts that depend on the user's path. You do
need to protect all the standard-location commands, but you should also
allow the user's path to remain. (I once saw an in-house shell
tutorial thatt showed a .profile with PATH=:/bin:/usr/bin:/4513/fred/bin: -
the user had tried it out and wondered why lots of useful commands
didn't work any more.)

There are a few other fun commands to have local versions of. One of
my users wrote a "sort", in Fortran. After he got it to compile, he
decided to add some features, and "f77 sort.f" died with ugly errors.
Seems the system V f77 compiler used "sort" to help with symbol tables,
and his sort routine didn't take the same arguments as /bin/sort.

--
# Bill Stewart, AT&T Bell Labs 2G-202, Holmdel NJ 1-201-949-0705 ihnp4!ho95c!wcs

ida...@watmath.uucp

unread,
Jan 2, 1986, 1:12:30 AM1/2/86
to
People who advocate setting the PATH variable and using "only"
relative path names in shell scripts are forgetting all the absolute
path names that they put in the PATH variable. Just as commands move
from search directory to search directory, so do search directories
change, either over time or among host machines. You can't use
hard-coded path names there, either!

We have several different UNIX systems going here, with the result that
the choice of paths in the PATH variable is not the same on all
machines. Beyond /bin and /usr/bin, which exist on every UNIX machine
we've ever heard of, the writer of a shell script destined for
distribution to all our machines does not know where a particular
machine is keeping a command; hence, s/he cannot hard-code a particular
set of directories at the start of a system shell script.

The choices of distributing different versions of shell scripts to
different machines or making the shell scripts set their PATH by
checking which machine they are on both suffer from having the path
information for a machine replicated in the scripts. If a machine
changes search paths, all the scripts have to be found and changed.

So, Waterloo took the leap and wrote a command, /bin/searchpath, whose
primary function is to return the list of standard search paths when
executed on a particular host. Using arguments, the command can also
return a list of paths suitable for use by "system maintainers", people
doing "accounting", etc. From the user's point of view, s/he selects
the type of commands s/he needs by category, and /bin/searchpath
supplies the places where they reside on the current host. The command
provides useful detail-hiding, since the pathnames themselves are
usually anachronistic and irrelevant to shell-script programmers.

We create and maintain a file on each host that has the search path
information for that host, for use by our command. "Porting" our shell
scripts to a new UNIX machine involves creating the file(s) containing
the search path information for that host. New shell scripts now start
with a command to set the PATH variable:

PATH="`/bin/searchpath type=users`"; export PATH

These scripts work on all our UNIX systems, no matter how odd the
search path structure is at that moment. We have a category of search
path for systems people, and it includes the "test" path(s) where we
put commands that we want to test before they get installed for real.
We are free to add, delete, and rename paths to suit our file system
space or program organization needs without requiring anyone (especially
overworked systems people) to change a single line of code. All our new
users are supplied with login profiles that set $PATH using /bin/searchpath.

So, our shell scripts only need to know *one* absolute pathname --
/bin/searchpath. The rest is done dynamically according to what kind
of search paths are needed and what host the script is running on.
The command requires a bit of overhead at the start of a shell script,
but, gosh, it sure makes life easier.
--
-IAN! (Ian! D. Allen) University of Waterloo

davi...@steinmetz.uucp

unread,
Jan 9, 1986, 10:13:04 AM1/9/86
to

A recent note on a utility which produced default user paths prompts me offer
a few ideas and ask for information.

On the SysIII and SysV systems with which I usually work, the default
user path is defined in /etc/profile, which is executed before the .profile.
This path includes the local command directory(s) for the machine as well. I
saw that the command the set the path was placed in /bin, while (as far as I
now) most of our machines have a separate directory for local commands. This
allows users to work with only standard commands if they desire, by editing
their path.

Question: do most people have a separate directory for local commands, and if
so what do you call it? Favorites here are /usr/local/bin and /usr/lbin.

Please mail info to me and I will summarize and post when the volume drops
off.
--
-bill davidsen

seismo!rochester!steinmetz!--\
/ \
ihnp4! unirot ------------->--- crdos1!davidsen
\ /
chinet! ---------------------/

"It seemed like a good idea at the time..."

0 new messages