http://www.perlmonks.org?node_id=533871

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

How do I remove a directory path from a scalar ? e.g.
$file = "/opt/local/bin/zap.exe"
I need to end up with
$file = "zap.exe"
So remove everything upto and including the last /
Any help appreciated

Replies are listed 'Best First'.
Re: remove directory path
by prasadbabu (Prior) on Mar 02, 2006 at 13:10 UTC

    You need to take a look at File::Basename

    or simply with regex

    $file = "/opt/local/bin/zap.exe"; $file =~ s|.*/||s; print $file; output: zap.exe

    updated: As per frodo72 suggestion. Thanks frodo72

    Prasad

      The File::Basename approach is better IMHO - more readable, portable and tested.

      In the regex, you're bound to be in some Unix flavour; moreover, it misses files in the root directory, because of the "+". I'd reword it as:

      $file =~ s{.*/}{}s;
      but the better choice remains File::Basename.

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.

      try this..

      $file = "/opt/local/bin/zap.exe"; print $file = (split(/\//, $file))[-1];

      try this..

      $file = "/opt/local/bin/zap.exe"; $file = (split(/\//, $file))[-1]; print $file;
Re: remove directory path
by gube (Parson) on Mar 02, 2006 at 14:14 UTC

    Hi try this,

    #!/usr/local/bin/perl use File::Basename; print $file_name = basename('/opt/local/bin/zap.exe');
Re: remove directory path
by helgi (Hermit) on Mar 02, 2006 at 14:12 UTC
    #!/bin/perl use warnings; use strict; use File::Basename; my $file = '//server/path/filename.ext'; print basename($file);


    --
    Regards,
    Helgi Briem
    hbriem AT f-prot DOT com
Re: remove directory path
by Praveen (Friar) on Mar 02, 2006 at 14:14 UTC
    Try This
    $file = "/opt/local/bin/zap.exe"; $file =~ s/.*\///g; print $file;
Re: remove directory path
by linux454 (Pilgrim) on Mar 02, 2006 at 14:55 UTC
    see node split string and always get last word.

    While using the File::Basename, File::Spec, or other similar module will certainly do what you are looking for, in this case it may be overkill.
    If there is absolutely no expectation of this script ever running on a non unix-ish platform why use a sledgehammer to drive a nail?

      Because your expectation is probably wrong.

      Nothing drives me up the wall faster than wanting to use a program that has no reason not to work on my platform of choice except for an assumption that could have been avoided with a moment's extra thought.

      Because it's harder to get a tyop when using File::Basename or File::Spec.

      You pass in a string. Everything else is caught at compile time. Mistyping in a regular expression won't be noticed unless you pay close attention to the output.

      Because using the module makes your code clear, concise, correct, and say what you mean.

      When comparing code using a regexp and code using File::Basename, isn't it much more obvious what the code using basename($path) is doing? Yes, you can sit there for a couple of seconds to assure yourself that $path =~ s{.*[\\/]}{} is working correctly. But it's immediately obvious what basename is doing. Self-commenting code is way better than code that needs comments to make it easier to follow.

      And then it's also solving the problem in the domain of the problem ("how do I get the basename of a file?") rather than in the domain of the solution ("by getting rid of everything up to, and including, the last delimiter"). This means that when something changes, it should be much more obvious what needs to be changed. It definitely makes things not only more maintainable, in my experience, but also more likely to withstand changes in requirements without actual code changes, or with fewer code changes.


      Need I go on? Besides, I think that a regular expression is more like a sledgehammer - it is a huge, powerful, generalised tool. Here we have a screw. You want to use a sledge hammer to drive a screw rather than a screwdriver.

        Nothing drives me up the wall faster than wanting to use a program that has no reason not to work on my platform of choice except for an assumption that could have been avoided with a moment's extra thought.

        You would be correct if the code in question is to be released to the general population. In the real world though, often scripts are written for a very specific task to be performed in a specific environment. If you only perform this task on *NIX systems and will only ever perform this task on *NIX systems, then I see no problem with making those types of assumptions. If this code is to be released for general consumption then your statement would be correct. Published code should be written with maximum portability in mind. However, I was wrong on one point, both the split and the regex solutions are not tied to *NIX platforms, they can be adapted to any platform by just changing the path separator, as the basename is always the last item in the path)

        Because it's harder to get a tyop when using File::Basename or File::Spec.

        You pass in a string. Everything else is caught at compile time. Mistyping in a regular expression won't be noticed unless you pay close attention to the output.

        I don't know where you get this notion, a typo is a typo, is a typo, no matter how you spin it. If you write code for any purpose and don't test it thoroughly then you are already in a heap of trouble. Using a module does not excuse one from testing.

        Because using the module makes your code clear, concise, correct, and say what you mean...

        You're right basename($path) is more concise than non-module solutions. But that is what comments are for. There is indeed a reason why 99% of all programming languages provide some mechanism for placing comments in the code. Or if you have to perform this all over the place, put it in an aptly named function which addresses your self-commenting code argument. I'm not a fan of obfuscating or even using some of the more sublte shortcuts of Perl for the very reason of readability and maintainability, but we are using some very basic facilities here.

        And then it's also solving the problem in the domain of the problem ("how do I get the basename of a file?") rather than in the domain of the solution ("by getting rid of everything up to, and including, the last delimiter").

        Call me crazy, but what does it matter so long as you get the basename of the path?

        This means that when something changes, it should be much more obvious what needs to be changed. It definitely makes things not only more maintainable, in my experience, but also more likely to withstand changes in requirements without actual code changes, or with fewer code changes.

        How do you figure that? Again let's assume that the regex or split solutions provided are moved into an appropriately named function, it becomes quite clear what needs to be changed. In this specific case, what expectations are going to change. If you want to talk generics, that's one thing, but this is a specific case. I can't think of what requirements will change in "give me the basename of the path". If the requirement that you need something other than the basename comes up, you are still going to have to change code to provide the new requirement. So I don't really see the merit of this argument.

        Regex and split a sledgehammer? Let's see one or two lines of code as opposed to all the overhead of the previously mentioned modules. I'll take the one or two lines of code which offer far less overhead and operations than the module. If other features were needed from these modules than just basename, I could see the justification for using a module.

        Here we have a screw.

        More like a carriage bolt. When a screw would do.

        Don't get me wrong, I am a great proponent of module use, where the situation warrants. But to use a module for the sake of using a module is just overkill.

        The simple truth of the matter is we are both right.