bernie@DIALix.oz.au (Bernd Felsche) (09/09/90)
In article <1990Sep7.152354.9439@ecn.purdue.edu> patkar@helium.ecn.purdue.edu (The Silent Dodo) writes: >I have a question about shell scripts. How can a shell script >(sh or csh) find out its own file name? Actually, I need to >know only the directory in which it resides. > The trivial solution is that the program name is in $0. Since you want the path (directory), it is only partially useful, because the program name is what you actually typed. So if you typed 'freddo', then $0 becomes that... no path. The solution is to parse the current PATH if the program name does not begin with a '/'. On a BSD machine, you can use the 'which' command (come Sys V have it also), or you can work it out by: : # bourne shell script template # prog=$0 case $prog in /*) echo $i break ;; *) OIFS="$IFS" IFS=":$IFS" for i in $PATH do if [ -x $i/$prog ] then break fi done echo $i/$prog IFS="$OIFS" ;; esac Instead of the echo's, you can use a fullname= etc to find what you need. To get the directory name is left as an exercise :-) bernie p.s. Send no cash. Just Bullion.
rsl@cbnewsm.att.com (randolph.little) (09/11/90)
In article <563@DIALix.UUCP>, bernie@DIALix.oz.au (Bernd Felsche) writes: > In article <1990Sep7.152354.9439@ecn.purdue.edu> patkar@helium.ecn.purdue.edu (The Silent Dodo) writes: > >I have a question about shell scripts. How can a shell script > >(sh or csh) find out its own file name? > > The solution is to parse the current PATH if the program name does > not begin with a '/'. On a BSD machine, you can use the 'which' > command (come Sys V have it also), or you can work it out by: > > : > # bourne shell script template > # > > prog=$0 > case $prog in > /*) echo $i # ^^^ Should be $0 > break > ;; # Add test for explicit current directory search: ./*) echo `pwd`/`basename $0` break ;; > *) > OIFS="$IFS" > IFS=":$IFS" > > for i in $PATH > do > if [ -x $i/$prog ] > then > break > fi > done > echo $i/$prog > IFS="$OIFS" > ;; > esac > > Instead of the echo's, you can use a fullname= etc to find what you > need. To get the directory name is left as an exercise :-) > > bernie > > p.s. Send no cash. Just Bullion. The first change corrects a typo, where $i should be $0; while the second change adds another pattern to handle the case where the command is invoked in the working directory by typing ./command (which bypasses $PATH). Randolph S. Little <randolph.little@att.com>
jimr@hp-lsd.COS.HP.COM (Jim Rogers) (09/13/90)
Following is a modest script in ksh to report the path of a script. I suspect that this can be done much more elegantly. The beauty of this script is that it works correctly. #! /bin/ksh # This script displays the path name of the script itself # from the command argument $0 name=$0 # look for the path in the above directory first=${name#..} if [ "$first" != "$name" ] then cd .. fpth=$PWD$first else # look for the path in the current directory first=${name#.} if [ "$first" != "$name" ] then fpth=$PWD$first else case $name in # Absolute path specified /*) fpath=$name; break;; # relative path below current directory *) fpath=$PWD/$name; break;; esac fi fi spath=`print $ppth | tr "/" " "` for file in $spath do continue done pth=${fpath%/$file} print "path to $name is $pth" Jim Rogers Hewlett Packard Company
anw@maths.nott.ac.uk (Dr A. N. Walker) (09/13/90)
In article <563@DIALix.UUCP> bernie@DIALix.oz.au (Bernd Felsche) writes: >In article <1990Sep7.152354.9439@ecn.purdue.edu> patkar@helium.ecn.purdue.edu (The Silent Dodo) writes: >>[...] How can a shell script >>(sh or csh) find out [the directory of] its own file name? > [gives shell script to parse the PATH] Just to point out that any such script is easily spoofed, in case this is a security- or accounting-related problem. Try something like $ PATH=/something/innocuous export PATH $ /bin/sh $ PATH=/secret/directory # note, no export $ spoof and "spoof" will look for itself in "/something/innocuous", even though it was found in "/secret/directory". At least, it does in SunOS 4.0.3, and it does with our somewhat modded SysV shell, though I don't remember seeing anywhere a definition of what *should* happen if an exported variable is masked by an unexported one. -- Andy Walker, Maths Dept., Nott'm Univ., UK. anw@maths.nott.ac.uk
bernie@DIALix.UUCP (Bernd Felsche) (09/15/90)
In article <1990Sep10.185245.25531@cbnewsm.att.com> rsl@cbnewsm.att.com (randolph.little) writes: >In article <563@DIALix.UUCP>, bernie@DIALix.oz.au (Bernd Felsche) writes: >> The solution is to parse the current PATH if the program name does >> not begin with a '/'. On a BSD machine, you can use the 'which' >> command (come Sys V have it also), or you can work it out by: >> [some script deleted] >> prog=$0 >> case $prog in >> /*) echo $i ># ^^^ Should be $0 >> break >> ;; ># Add test for explicit current directory search: > ./*) echo `pwd`/`basename $0` ^^^^^^^^^^^^^^^^^ This will break if somebody uses ./bin/whodo or something. Even worse, you (and I) neglected to check for the existence and execute permissions. What about ../* ?? After posting, I did notice the deficiency, (actually woke up in the middle of the night!) I trust that the end-use is not in a life-threatening environment :-) > break I could use one... [...rest of script deleted...] > >The first change corrects a typo, where $i should be $0; while the Sprung! I actually kludged my "which" script to include in the message. >second change adds another pattern to handle the case where the command >is invoked in the working directory by typing ./command (which bypasses $PATH). > >Randolph S. Little <randolph.little@att.com> Thank you for your vigilance. Constructive criticism should be rewarded. So here's the which script, it can be easily tailored to suit the original request... barring typos! Some serious testing has gone into this, so please let me know if I've missed something. I don't want to put shell function (or korn shell aliases) into it. If you're that way inclined, please post the results. ------------------------------- cut here ----------------------- : # bourne shell which # # which what? :-) # # By Bernd Felsche. bernie@DIALix.oz.au # # bug with relative paths fixed Sat Sep 15 17:23:32 WST 1990 # if [ $# = 0 ] then echo "usage: $0 program [program...]" 1>&2 exit 1 fi for prog in $* ; do path="NO PATH AVAIL" case $prog in /*) path=$i ;; ./*|../*) dir=`dirname $prog` if [ -d $dir ] ; then path=`(eval cd $dir ; pwd)`/`basename $prog` fi ;; *) OIFS="$IFS" IFS=":$IFS" for i in $PATH ; do if [ -f $i/$prog -a -x $i/$prog ] ; then path=$i/$prog break # for $PATH fi done IFS="$OIFS" ;; esac if [ -x $path -a -f $path ] ; then echo $path else echo $prog not found 1>&2 exit 2 fi done ------------------------- end ----------------------- bernie P.S. bug reports & critiques welcome.
bernie@DIALix.UUCP (Bernd Felsche) (09/15/90)
In article <1990Sep13.151130.10215@maths.nott.ac.uk> anw@maths.nott.ac.uk (Dr A. N. Walker) writes: > Just to point out that any such script is easily spoofed, in case >this is a security- or accounting-related problem. Try something like > > $ PATH=/something/innocuous export PATH > $ /bin/sh > $ PATH=/secret/directory # note, no export > $ spoof > >and "spoof" will look for itself in "/something/innocuous", even though it >was found in "/secret/directory". At least, it does in SunOS 4.0.3, and it >does with our somewhat modded SysV shell, though I don't remember seeing >anywhere a definition of what *should* happen if an exported variable is >masked by an unexported one. IMHO: Your shell is broken. Not my script. On all the real bourne shells I've tested this on (two so far) the results are dependent on the _environment_ PATH setting. Your shell is not using PATH as set in the environment, only its internal working space value. Perhaps somebody on the net can elucidate as to the divergence in philosophy. (I get polysyllabic after 6 hours of reading news.) bernie.
anw@maths.nott.ac.uk (Dr A. N. Walker) (09/19/90)
In article <572@DIALix.UUCP> bernie@DIALix.oz.au (Bernd Felsche) writes: [re my comment that any script that determines how it was called is easily spoofed] >IMHO: Your shell is broken. Not my script. On all the real bourne >shells I've tested this on (two so far) the results are dependent on >the _environment_ PATH setting. > >Your shell is not using PATH as set in the environment, only its >internal working space value. Well, our PDP 11 is now deceased, so I can't run a *real* Bourne shell [the one in pseudo Algol] without compiling up the source, but I think you have misunderstood "my" result. Sorry if this was caused by lack of clarity in the original; let me try again. Suppose I am running a shell [A], and invoke a sub-shell [B]. In B, I set "PATH=/something/or/other", without exporting it. This PATH is now used to find commands. I invoke a shell script "spoof". This script is run with $0 set to "spoof", but it does *not* inherit PATH from B. Thus "spoof" is actually "/something/or/other/spoof", but there is nothing in the environment *of "spoof"* that enables it to recover this information. In the shells instantly available to me, PATH is in fact inherited from A, so anything that *"spoof"* does to discover how it was called is likely to be wrong, depending on the ingenuity of the PATH setting in A. By working slightly harder (eg, writing a C program), "spoof" can be supplied with whatever $0 and PATH (or anything else in the environment, such as IFS) a bad guy likes. Thus, any shell script that includes code like case $0 in foo) some command esac is insecure. Of course, code that searches "$PATH" is perfectly OK for run-of-the-mill utility scripts, where only the caller is hurt if the script does something unexpected. -- Andy Walker, Maths Dept., Nott'm Univ., UK. anw@maths.nott.ac.uk
gt0178a@prism.gatech.EDU (BURNS) (09/19/90)
in article <571@DIALix.UUCP>, bernie@DIALix.UUCP (Bernd Felsche) says:
[supplies expanded which script]
I saved your script as I thought it was an interesting piece of work, but
I will point out a couple of problems:
1) The easy one was my (Dynix's) version of sh didn't like your syntax for
test(1), so I used ksh.
2) If you do (your script is called wh):
wh wall # you get:
wall not found
Similarly, w/ the system supplied which:
which wall # you get:
no wall in . /hydra9/gt01/gt0178a /usr/local/bin /usr/ucb /bin /usr/bin /usr/att/bin /usr/att/usr/bin
which is of course my path. Finally, the system supplied (at least for me)
whereis gives:
ll `whereis wall` # you get:
wall: not found
-rwxr-x--- 1 root 20480 May 21 1988 /bin/wall*
-r--r--r-- 1 root 984 May 21 1988 /usr/man/man1/wall.1
Ignore the 1st line, unless it is the only one. Obviously wall is failing
the executable test in the 1st 2 commands. Moral - don't stick to one tool
(there are lots of things whereis can't find).
--
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp: ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu
bernie@DIALix.UUCP (Bernd Felsche) (09/21/90)
Lesson 1: I can make misteaks too. The method I used to check for the PATH was to create a temporary file in the current directory, with a pleasing message inside. I exported my current PATH, starting with /bin, and then prepended my normal path with ".", (it's usually at the end), and executed the command. The command name was that of a command in the /bin directory, with my own version in . Suffice to say, I got the result expected from executing the /bin command. Misteak: The name of the command was test. This is of course, a builtin in modern shells, so it got executed without refernce to the PATH at all. In article <13838@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS) writes: >in article <571@DIALix.UUCP>, bernie@DIALix.UUCP (Bernd Felsche) says: > >[supplies expanded which script] > >I saved your script as I thought it was an interesting piece of work, but >I will point out a couple of problems: :-( > >1) The easy one was my (Dynix's) version of sh didn't like your syntax for >test(1), so I used ksh. Lesson 2: no two shells are alike, even if they are superficially the same. I often find subtle differences between BSD, V.0, V.2, V.3 and XENIX /bin/sh. Using ksh is a good idea, because it's newer and less versions proliferate... at the moment. Perhaps you can tell me which test syntax Dynix is happy with. (Don't grumble. It takes practice to find prepositions to end a sentence with :-) ) > >2) If you do (your script is called wh): > >wh wall # you get: >wall not found > >Similarly, w/ the system supplied which: > >which wall # you get: >no wall in . /hydra9/gt01/gt0178a /usr/local/bin /usr/ucb /bin /usr/bin /usr/att/bin /usr/att/usr/bin > >which is of course my path. Finally, the system supplied (at least for me) >whereis gives: > >ll `whereis wall` # you get: >wall: not found >-rwxr-x--- 1 root 20480 May 21 1988 /bin/wall* ^^^^^^^^^^ Does this mean that you wouldn't have been able to execute it anyway? If you type "wall", don't you get a permission denied? >-r--r--r-- 1 root 984 May 21 1988 /usr/man/man1/wall.1 > >Ignore the 1st line, unless it is the only one. Obviously wall is failing >the executable test in the 1st 2 commands. Moral - don't stick to one tool >(there are lots of things whereis can't find). The purpose of the which tool is to tell you _which_ command will be executed. It is designed to be quick. It does not attempt to interpret functions, aliases or similar creatures. The output of whereis above is useful only if you change your gid or uid, after which (no pun), wh will find wall. >-- >BURNS,JIM Thanks for the beta testing, Jim. Production releases of "which" (V12.09.06.20) will be shipped RSN, at a cost of US$825. :-) Order now and avoid the rush. bernie p.s. Misteaks are deliberate.
gt0178a@prism.gatech.EDU (BURNS,JIM) (09/22/90)
in article <574@DIALix.UUCP>, bernie@DIALix.UUCP (Bernd Felsche) says: > Misteak: The name of the command was test. This is of > course, a builtin in modern shells, so it got executed > without refernce to the PATH at all. He-he-he. > Perhaps you can tell me which test syntax Dynix is happy > with. (Don't grumble. It takes practice to find prepositions > to end a sentence with :-) ) Basically, our sh seems to use /bin/test. You get the same errors in ksh if you replace the []'s with /bin/test. It didn't like '-x'. I'll mail you the relevant man pages from test(1) and ksh(1). >>-rwxr-x--- 1 root 20480 May 21 1988 /bin/wall* > ^^^^^^^^^^ > Does this mean that you wouldn't have been able to execute it > anyway? If you type "wall", don't you get a permission denied? Yes. > The purpose of the which tool is to tell you _which_ command will be > executed. It is designed to be quick. It does not attempt to > interpret functions, aliases or similar creatures. I'm using it to find out where an executable lives. Useful if your system has several versions, and which you execute depends on how your PATH is ordered. And since I *can't* execute wall(1) (or finger(1)) on that machine, locating it tells me why - it's not that it's not there, just that it's not world executable. By extension, I have an $ETC variable I can also search for the occaisional command that's not normally in my $PATH, like ping(1). -- BURNS,JIM Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332 uucp: ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a Internet: gt0178a@prism.gatech.edu
meissner@osf.org (Michael Meissner) (09/23/90)
In article <13992@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS,JIM) writes: | > The purpose of the which tool is to tell you _which_ command will be | > executed. It is designed to be quick. It does not attempt to | > interpret functions, aliases or similar creatures. | | I'm using it to find out where an executable lives. Useful if your system | has several versions, and which you execute depends on how your PATH is | ordered. And since I *can't* execute wall(1) (or finger(1)) on that | machine, locating it tells me why - it's not that it's not there, just | that it's not world executable. By extension, I have an $ETC variable I | can also search for the occaisional command that's not normally in my | $PATH, like ping(1). I like bash's type -all feature, where you can find all occurances of a command in the PATH. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142 Do apple growers tell their kids money doesn't grow on bushes?
gwyn@smoke.BRL.MIL (Doug Gwyn) (09/23/90)
In article <MEISSNER.90Sep22142134@osf.osf.org>, meissner@osf.org (Michael Meissner) writes: > I like bash's type -all feature, where you can find all occurances of > a command in the PATH. Or, assuming PATH is exported, you can use a shell script like this: #!/usr/5bin/sh # which, every -- which cmd in PATH is executed # adapted from Kernighan & Pike # last edit: 85/03/07 D A Gwyn # SCCS ID: @(#)which.sh 1.4 opath=$PATH PATH=/usr/5bin:/bin:/usr/bin name=`basename $0` # "which" or "every" if [ $# -eq 0 ] then echo Usage: $name 'command(s)' 1>&2 exit 2 fi prefixes=`echo $opath | sed 's/^:/.:/ s/::/:.:/g s/:$/:./ s/:/ /g'` ex=1 # assume nothing found for cmd in $* do nf=1 # assume cmd not found case $cmd in /*) if [ -f $cmd -a -x $cmd ] then echo $cmd nf=0 # found it fi ;; *) for pfx in $prefixes do if [ -f $pfx/$cmd -a -x $pfx/$cmd ] then echo $pfx/$cmd nf=0 # found it if [ $name = which ] then break fi fi done ;; esac if [ $nf -ne 0 ] then echo $name: $cmd: 'not found' 1>&2 else ex=0 # found one fi done exit $ex
chet@cwns1.CWRU.EDU (Chet Ramey) (09/25/90)
In article <MEISSNER.90Sep22142134@osf.osf.org> meissner@osf.org (Michael Meissner) writes: >I like bash's type -all feature, where you can find all occurances of >a command in the PATH. Bash's `type' command is very nice. I have written shell functions implementing ksh `whence', csh `which', 10th edition sh `whatis', and regular bsh `type' using it, so everything else that's out there in wide use can be implemented using it. Chet -- Chet Ramey ``Levi Stubbs' tears run down Network Services Group his face...'' Case Western Reserve University chet@ins.CWRU.Edu