简体   繁体   中英

How can I extract a filename from a path using Perl?

I have a Perl variable I populate from the database. Its name is $path . I need to get another variable $file which has just the filename from the pathname.

I tried:

$file = $path =~ s/.*\///;

I am very new to Perl.

Why reinvent the wheel? Use the File::Basename module:

use File::Basename;
...
$file = basename($path);

Why did $file=$path=~s/.*\\///; not work?

=~ has higher precedence than =

So

$file = $path =~s/.*\///;

is treated as:

$file = ($path =~s/.*\///);

which does the replacement in $path and assigns either 1 (if replacement occurs) or '' (if no replacement occurs).

What you want is:

($file = $path) =~s/.*\///;

which assigns the value of $path to $file and then does the replacement in $path .

But again there are many problems with this solution:

  1. It is incorrect. A filename in Unix based systems (not sure about Windows) can contain newline. But . by default does not match a newline. So you'll have to use a s modifier so that . matches newline as well:

     ($file = $path) =~s/.*\\///s;
  2. Most importantly it is not portable as it is assuming / is the path separator which is not the case with some platforms like Windows (which uses \\ ), Mac (which uses : ). So use the module and let it handle all these issues for you.

use File::Basename 

Check the below link for a detailed description on how it works:

http://p3rl.org/File::Basename

I think the best way of doing this is -

use File::Basename;

my $file_name = basename($0);

So the variable $file_name will have the name of your script

Path::Class may seem like overkill at first—making objects of file and dir paths—but it can really pay off in complicated scripts and offers lots of bonuses that will prevent spaghetti when you get backed into a corner by scope creep. File::Spec is used in the first example for fun to resolve path.

use warnings;
use strict;
use Path::Class qw( file );
use File::Spec;

# Get the name of the current script with the procedural interface-
my $self_file = file( File::Spec->rel2abs(__FILE__) );
print
    " Full path: $self_file", $/,
    "Parent dir: ", $self_file->parent, $/,
    " Just name: ", $self_file->basename, $/;

# OO                                    
my $other = Path::Class::File->new("/tmp/some.weird/path-.unk#");
print "Other file: ", $other->basename, $/;
$url=~/\/([^\/]+)$/;
print "Filename $1\n";

As easy as that:

$path =~ /.*[\/\\](.*)/;    # will return 1 (or 0) and set $1
my $file = $1;              # $1 contains the filename

To check if an filename is available use:

$file = $1 if $path =~ /.*[\/\\](.*)/;

The pattern:

.*[\/\\](.*)
| |     |
| |     \- at last there is a group with the filename
| \------- it's the last / in linux or the last \ in windows
\--------- .* is very greedy, so it takes all it could

Use eg https://regex101.com/ to check regular expressions.

Extracting file name from path is very easy for both Unix and Windows file systems without need any packages:

my $path;
$path = 'C:\A\BB\C\windows_fs.txt';     # Windows
#$path = '/a/bb/ccc/ddd/unix_fs.txt';    # Unix

my $file =  (split( /\/|\\/, $path))[-1];
print "File: $file\n";

# variable $file is "windows_fs.txt"  for Windows
# variable $file is "unix_fs.txt"     for Unix

The logic is very simple: create an array of all elements making the path and retrieve the last one. Perl allows to use negative indexes starting from end of the array. Index "-1" corresponds to the last element.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM