New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
File::Basename behavior is misleading #6521
Comments
From frederik@ugcs.caltech.eduCreated by frederik@ugcs.caltech.eduThe File::Basename man page suggests that the basename and dirname $ dirname a/ . Here $f="a/", and dirname($f)."/".basename($f)="./". Perl Info
|
From sorourke@cs.ucsd.eduThis makes dirname($f)."/".basename($f) point to the same file as $f $f = "/usr/lib//"; Tested on Darwin. /s |
From sorourke@cs.ucsd.edufoo.patch--- /opt/perl/lib/5.8.0/File/Basename.pm.old Fri Jul 19 19:00:58 2002
+++ /opt/perl/lib/5.8.0/File/Basename.pm Sun Jul 6 20:57:48 2003
@@ -104,6 +104,11 @@ The basename() routine returns the first
by calling fileparse() with the same arguments, except that it always
quotes metacharacters in the given suffixes. It is provided for
programmer compatibility with the Unix shell command basename(1).
+Like the dirname() routine, basename() emulates the Unix behavior,
+which may not be consistent with fileparse. For example, for the
+input file specification F<lib/>, fileparse() returns the empty string
+as the file's basename, while basename() returns F<lib> (without the
+trailing slash(es)).
=item C<dirname>
@@ -231,9 +236,19 @@ sub fileparse {
# basename() - returns first element of list returned by fileparse()
+# on non-UNIX/Win/DOS systems, otherwise returns the result of
+# basename(1) (see below
sub basename {
my($name) = shift;
+ my($fstype) = $Fileparse_fstype;
+
+ if ($fstype =~ /MS(DOS|Win32)|os2/i) {
+ $name =~ s/([^:])[\\\/]*\z/$1/;
+ }
+ elsif ($fstype !~ /MacOS|VMS|AmigaOS/i) {
+ $name =~ s:(.)/*\z:$1:s;
+ }
(fileparse($name, map("\Q$_\E",@_)))[0];
}
|
From @schwern[sorourke@cs.ucsd.edu - Sun Jul 13 12:04:02 2003]:
My only issue with this patch is it contradicts the existing docs... The basename() routine returns the first element of the list pro- Except the existing docs contradict itself. It is provided for programmer compatibility with the Unix So EITHER it works the same as fileparse() OR it works the same as Attached is a patch to make basename() strip trailing path seperators |
From @schwernfb.patch--- lib/File/Basename.pm 2005/07/06 16:11:06 1.3
+++ lib/File/Basename.pm 2005/07/06 19:30:56
@@ -22,6 +22,13 @@
the shell and C functions of the same name. See each function's documention
for details.
+It is guaranteed that
+
+ # Where $path_separator is / for Unix, \ for Windows, etc...
+ dirname($path) . $path_separator . basename($path);
+
+is equivalent to the original path for all systems but VMS.
+
=cut
@@ -172,21 +179,32 @@
my $filename = basename($path);
my $filename = basename($path, @suffixes);
-C<basename()> works just like C<fileparse()> in scalar context - you only get
-the $filename - except that it always quotes metacharacters in the @suffixes.
+This function is provided for compatibility with the Unix shell command
+C<basename(1)>. It does B<NOT> always return the file name portion of a
+path as you might expect. To be safe, if you want the file name portion of
+a path use C<fileparse()>.
+
+C<basename()> returns the last level of a filepath even if the last
+level is clearly directory. In effect, its acting like C<pop()> for
+paths. This differs from fileparse()'s behavior.
+
+ # Both return "bar"
+ basename("/foo/bar");
+ basename("/foo/bar/");
+
+@suffixes work as in fileparse() except all regex metacharacters are
+quoted.
# These two function calls are equivalent.
my $filename = basename("/foo/bar/baz.txt", ".txt");
my $filename = fileparse("/foo/bar/baz.txt", qr/\Q.txt\E/);
-This function is provided for compatibility with the Unix shell command
-C<basename(1)>.
-
=cut
sub basename {
my($name) = shift;
+ _strip_trailing_sep($name);
(fileparse($name, map("\Q$_\E",@_)))[0];
}
@@ -251,16 +269,16 @@
}
elsif ($type eq 'MacOS') {
if( !length($basename) && $dirname !~ /^[^:]+:\z/) {
- $dirname =~ s/([^:]):\z/$1/s;
+ _strip_trailing_sep($dirname);
($basename,$dirname) = fileparse $dirname;
}
$dirname .= ":" unless $dirname =~ /:\z/;
}
elsif (grep { $type eq $_ } qw(MSDOS DOS MSWin32 OS2)) {
- $dirname =~ s/([^:])[\\\/]*\z/$1/;
+ _strip_trailing_sep($dirname);
unless( length($basename) ) {
($basename,$dirname) = fileparse $dirname;
- $dirname =~ s/([^:])[\\\/]*\z/$1/;
+ _strip_trailing_sep($dirname);
}
}
elsif ($type eq 'AmigaOS') {
@@ -269,14 +287,30 @@
$dirname =~ s#[^:/]+\z## unless length($basename);
}
else {
- $dirname =~ s{(.)/*\z}{$1}s;
+ _strip_trailing_sep($dirname);
unless( length($basename) ) {
($basename,$dirname) = fileparse $dirname;
- $dirname =~ s{(.)/*\z}{$1}s;
+ _strip_trailing_sep($dirname);
}
}
$dirname;
+}
+
+
+# Strip the trailing path separator.
+sub _strip_trailing_sep {
+ my $type = $Fileparse_fstype;
+
+ if ($type eq 'MacOS') {
+ $_[0] =~ s/([^:]):\z/$1/s;
+ }
+ elsif (grep { $type eq $_ } qw(MSDOS DOS MSWin32 OS2)) {
+ $_[0] =~ s/([^:])[\\\/]*\z/$1/;
+ }
+ else {
+ $_[0] =~ s{(.)/*\z}{$1}s;
+ }
}
--- lib/File/Basename.t 2005/07/06 16:11:57 1.3
+++ lib/File/Basename.t 2005/07/06 19:24:07
@@ -5,7 +5,7 @@
@INC = '../lib';
}
-use Test::More tests => 53;
+use Test::More tests => 57;
BEGIN { use_ok 'File::Basename' }
@@ -118,6 +118,16 @@
is(dirname('/perl/'), '/');
# perl5.003_18 gives '/perl/lib'
is(dirname('/perl/lib//'), '/perl');
+}
+
+### rt.perl.org 22236
+{
+ is(basename('a/'), 'a');
+ is(basename('/usr/lib//'), 'lib');
+
+ fileparse_set_fstype 'MSWin32';
+ is(basename('a\\'), 'a');
+ is(basename('\\usr\\lib\\\\'), 'lib');
}
|
From @steve-m-hayMichael G Schwern via RT wrote:
Thanks - applied as change 25090 (with one or two C<>'s again). Radan Computational Ltd. The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only. If you have received this message in error or there are any problems, please notify the sender immediately. The unauthorized use, disclosure, copying or alteration of this message is strictly forbidden. Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd. The recipient(s) of this message should check it and any attached files for viruses: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email. |
From @steve-m-hayPatch now applied, as noted above. |
@steve-m-hay - Status changed from 'open' to 'resolved' |
Migrated from rt.perl.org#22236 (status was 'resolved')
Searchable as RT22236$
The text was updated successfully, but these errors were encountered: