[comp.unix.questions] Wanted: How to strip off pathnames to obtain filenames.

dmk@pilot.njin.net (David Katinsky) (09/02/88)

Try the command `basename`.



					dmk
-- 
			      David M. Katinsky
			      
	       dmk@pilot.njin.net 	{wherever}!rutgers!dmk

chris@mimsy.UUCP (Chris Torek) (09/02/88)

In article <5968@ihlpf.ATT.COM> pcl@ihlpf.ATT.COM (pcl) writes:
>My question is, given a full or partial pathname, how to obtain the
>last field (which is the filename) in a straight foward manner.

>   filename=`echo $pathname | cut -fLAST -d/"	# no such thing -fLAST
>or
>   IFS=/
>   set $pathname	
>   filename=$`$#`		# I know this does not work

Actually, the latter almost works; the command

	eval 'filename=$'$#

works every time . . . until there are 10 or more components to the
path name.  `$13' produces $1 followed by the character 3, not the
thirteenth argument.  (Grr :-) )

There is a C-shell built-in that does it:

	set filename=$pathname:t	# or, better, :t:q

but you may not have the C shell available.

In that case, sed to the rescue!:

	filename=`echo $pathname | sed 's,.*/,,'`

>I know the following script does work (by brute force) but I could not put
>it in the same script (pathname args will be wiped out by the "set" command).
>
>	while [ "$#" -gt 1 ]
>	do
>		shift
>	done
>	echo $1

True.  But here is a strange thought: one can make all variables
`local' by using `-evaluation and subshells:

	filename=`while [ $# -gt 1 ]; do shift; done; echo $1`
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ok@quintus.uucp (Richard A. O'Keefe) (09/02/88)

In article <5968@ihlpf.ATT.COM> pcl@ihlpf.ATT.COM (pcl) writes:
>My question is, given a full or partial pathname, how to obtain the
>last field (which is the filename) in a straight foward manner.

If you have the 'basename' command, that does what you want.
An example:
	$ FullName=/this/is/just/a/test
	$ basename $FullName
	test
	$ dirname $FullName
	/this/is/just/a

wnp@dcs.UUCP (Wolf N. Paul) (09/02/88)

In article <5968@ihlpf.ATT.COM> pcl@ihlpf.ATT.COM (pcl) writes:
>My question is, given a full or partial pathname, how to obtain the
>last field (which is the filename) in a straight foward manner.
>
>Is there such command that does 
>   filename=`echo $pathname | cut -fLAST -d/"	# no such thing -fLAST

YES! basename(1) does exactly what you want!


	filename=`basename $pathname`

will yield the part of $pathname to the right of the last slash;

	filename=`basename $pathname .ext`

will yield the part of the pathname to the right of the last slash, minus
the extension ".ext".

Under System V Release 2, basename(1) is a shell script, so even if it does
not exist on your system (why would that be?) I'm sure you can find it 
somewhere within your organization (your corporate security wouldn't like
it if I posted it :-)).

However, this is also very straightforward to do in C:

#include <stdio.h>
#include <string.h>
main(argc, argv)
int argc;
char **argv;
{
	char *ptr;

	ptr=strrchr(argv[1], '/');
	*ptr++;
	puts(ptr);
}

Of course, if you are using C-Shell, things are even simpler:

	set filename=$pathname:t     # = basename $pathname
	set filename=$pathname:t:r   # = basename $pathname .*

etc.

-- 
Wolf N. Paul * 3387 Sam Rayburn Run * Carrollton TX 75007 * (214) 306-9101
UUCP:     killer!dcs!wnp                 ESL: 62832882
DOMAIN:   dcs!wnp@killer.dallas.tx.us    TLX: 910-380-0585 EES PLANO UD

morrell@hpsal2.HP.COM (Michael Morrell) (09/02/88)

/ hpsal2:comp.unix.questions / pcl@ihlpf.ATT.COM (pcl) /  4:07 pm  Sep  1, 1988 /
My question is, given a full or partial pathname, how to obtain the
last field (which is the filename) in a straight foward manner.

P. C. Liu		pcl@ihlpf.ATT.COM
----------

You could use "echo $filename | sed 's/.*\///'", but using basename(1) is
much easier.

   Michael

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (09/02/88)

In article <194@dcs.UUCP> wnp@dcs.UUCP (Wolf N. Paul) writes:
	[discussion of basename deleted]

>However, this is also very straightforward to do in C:
>#include <stdio.h>
>#include <string.h>
>main(argc, argv)
>int argc;
>char **argv;
>{
>	char *ptr;
>
>	ptr=strrchr(argv[1], '/');
>	*ptr++;
>	puts(ptr);
>}
>
>Wolf N. Paul * 3387 Sam Rayburn Run * Carrollton TX 75007 * (214) 306-9101

Almost.  It should be:

	#include <stdio.h>
	#include <string.h>

	main(argc, argv)
		int argc; char *argv[];
	{
		char *ptr;

		if ((ptr = strchr(argv[1], '/')) == NULL)
			ptr = argv[1];
		else
			ptr++;

		puts(ptr);
	}

strchr can return NULL when there are no chars in the string that match
the char you are searching for.

-- 
Larry Cipriani, AT&T Network Systems, Columbus OH, cbnews!lvc lvc@cbnews.ATT.COM

ado@elsie.UUCP (Arthur David Olson) (09/04/88)

> Almost.  It should be:
> 
> 	#include <stdio.h>
> 	#include <string.h>
> 
> 	main(argc, argv)
> 		int argc; char *argv[];
> 	{
> 		char *ptr;
> 
> 		if ((ptr = strchr(argv[1], '/')) == NULL)
> 			ptr = argv[1];
> 		else
> 			ptr++;
> 
> 		puts(ptr);
> 	}

Let's try again:

	#ifndef lint
	#ifndef NOID
	static char	sccsid[] = "@(#)usend.c	1.1";
	#endif /* !defined NOID */
	#endif /* !defined lint */

	#include <stdio.h>
	#include <string.h>

	#ifndef EXIT_SUCCESS
	#define EXIT_SUCCESS	0
	#endif /* !defined EXIT_SUCCESS */

	#ifndef EXIT_FAILURE
	#define EXIT_FAILURE	1
	#endif /* !defined EXIT_FAILURE */

	extern int	optind;

	int
	main(argc, argv)
	int	argc;
	char *	argv[];
	{
		register char *	ptr;

		if (getopt(argc, argv, "") != EOF || optind != argc - 1) {
			(void) fprintf(stderr, "%s: usage is %s filename\n",
				argv[0], argv[0]);
			exit(EXIT_FAILURE);
		}
		if ((ptr = strrchr(argv[optind], '/')) == NULL)
			ptr = argv[optind];
		else	++ptr;
		(void) puts(ptr);
		if (ferror(stdout) || fflush(stdout)) {
			(void) fprintf(stderr,
				"%s: wild result writing standard output\n",
				argv[0]);
			exit(EXIT_FAILURE);
		}
		exit(EXIT_SUCCESS);
		/*NOTREACHED*/
	}

Notes:

1.	The program now return an exit status.
2.	The program now checks that it is being used correctly.
	In particular, it avoids potential NULL pointer dereferencing if you use
		usend
	by itself on the command line.
3.	The program prints a usage message if it detects incorrect usage.
4.	The program checks that the output it generated actually got out
	(rather than, say, being directed to a full disk).
5.	The program calls getopt, even though it has no options, so that
	this program will handle "--", as in
		usend -- -a/b
	as other "standard" programs do.

Of course, around this neck of the woods we just "basename".
-- 
	ado@ncifcrf.gov			ADO is a trademark of Ampex.

gandalf@csli.STANFORD.EDU (Juergen Wagner) (09/06/88)

If you are using csh, how about:

	% set foo = /usr/john/foo/bar/src/misc/other/bugs/nil.bang
	% echo ${foo:t}
	nil.bang
	%

-- 
Juergen "Gandalf" Wagner,		   gandalf@csli.stanford.edu
Center for the Study of Language and Information (CSLI), Stanford CA

tim@attdso.ATT.COM (Tim J Ihde) (09/09/88)

In article <5968@ihlpf.ATT.COM> pcl@ihlpf.ATT.COM (pcl) writes:
>My question is, given a full or partial pathname, how to obtain the
>last field (which is the filename) in a straight foward manner.
>
>Is there such command that does 
>   filename=`echo $pathname | cut -fLAST -d/"	# no such thing -fLAST

The basename and dirname commands will do this, as I'm sure someone has
said by now.

For yet another path parser, you could do this with the much underutilized
expr command as well (at least on System V; I can't remember if BSD
does this or not).  In addition to doing math, expr will match regular
expressions for you and return part of the expression on stdout.  To
emulate basename you could use
	
	filename=`expr $pathname : '.*/\(.*)'`

The second regular expression in parenthesis is returned on stdout.
Note that the parens themselves must be escaped (if you don't include
any parens then expr returns the number of characters it matched).
These are ed style r.e.'s; so you need ".*" and not just "*" as a wildcard.
Since the first r.e., ".*/", will match as much as possible from $pathname, the
.* in the parens will always be the filename.

This is a more general path parser, since it could also return, say, the
last directory in the path before the filename:

	lastdir=`expr $pathname : '.*/\(.*)/.*'`

The use for such a beast is left as an exercise.  I've found

	suffix=`expr $pathname : '.*\.\(.*\)'`

to pull the "c" out of "file.c" useful several times.
-- 
Tim J Ihde					att!attdso!tim
(201) 898-6687					tim@attdso.att.com
This disclaimer intentionally left blank.  	attmail!tihde

runyan@hpirs.HP.COM (Mark Runyan) (09/10/88)

>/ gandalf@csli.STANFORD.EDU (Juergen Wagner) /  5:50 pm  Sep  5, 1988 /
>If you are using csh, how about:
>
>	% set foo = /usr/john/foo/bar/src/misc/other/bugs/nil.bang
>	% echo ${foo:t}
>	nil.bang
>	%

And, if you are using ksh, how about:

  $ foo=/usr/john/foo/bar/src/misc/other/bugs/nil.bang
  $ echo ${foo##/*/}
  nil.bang
  $


Mark "...Just found that one today..." Runyan