1

Directory path "/home/PPP/main/windows/agile/cmPvt" has aaa, bbb, ccc, ddd as its contents.

Code Snippet:

use File::Basename;
my $kkLoc = ("/home/PPP/main/windows/agile/cmPvt");
my @kkarray = glob("$kkLoc/*") if (-e $kkLoc);
foreach my $kknum (@kkarray) {  ## Here: see below
}   

Here: here I want that in @kkarray, "aaa", "bbb", "ccc", "ddd" shall come, but I am getting the whole path like "/home/PPP/main/windows/agile/cmPvt/aaa", "/home/PPP/main/windows/agile/cmPvt/bbb",.... Also, I tried, foreach my $kknum (basename "@kkarray") { }, but not working.

How can I get the "basename" from the full path while doing glob()?

Note: I can't do chdir to the path before executing glob command due to a reason.

TLP
  • 66,756
  • 10
  • 92
  • 149
PPP
  • 329
  • 1
  • 9
  • What is this "a reason"? – TLP Mar 19 '22 at 12:02
  • 1
    Note that `my ... if ...;` is non-sense and now allowed. You want `my @kkarray = -e $kkLoc ? glob(...) : ();` – ikegami Mar 19 '22 at 18:38
  • Note that your code suffers from a code injection bug. You need to convert the directory name into a glob pattern. `glob("\Q$kkLoc\E/*")` would work on unix. No easy way on Windows. – ikegami Mar 19 '22 at 18:40

3 Answers3

3

You tried to use a string with the interpolated array as argument to basename. That is wrong. You should take the individual paths, not all the paths concatenated together.

for my $path (@paths) { 
    print "Basename is: ", basename($path);
}

It says in the documentation how you should use the basename function:

my $filename = basename($path);
my $filename = basename($path, @suffixes);

This function is provided for compatibility with the Unix shell command basename(1). It does 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 fileparse().

basename() returns the last level of a filepath even if the last level is clearly directory. In effect, it is acting like pop() for paths. This differs from fileparse()'s behaviour.

# Both return "bar"
basename("/foo/bar");
basename("/foo/bar/");

You should note that by removing the full paths from the glob, that you cannot access the files if you cannot also chdir to their location, like you said you could not do "for a reason". So this whole exercise might be quite pointless for you.

You might like to look at File::Find which does a similar thing, recursively, and automatically allows you to select basename or full name. Like an all in one package.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • Thanks @TLP for the answer. Your first part is a workaround and is useful. – PPP Mar 22 '22 at 08:04
  • @PPP Well, its not a workaround, that is how you use `basename()` on array elements in a non-destructive way. – TLP Mar 22 '22 at 10:51
  • Yes @TLP, but I found \@toolic way more compact. It's one of the same thing though. – PPP Mar 22 '22 at 11:26
  • @PPP It is hardly "way more compact". It is using the `map` function. But as you say, its the same basic idea. – TLP Mar 22 '22 at 21:43
2

You can use map to call basename on each element of the array:

foreach my $kknum (map { basename($_) } @kkarray) {
}

This keeps the full path in the array variable, if that is desired.

If you never want the full path in the array variable, you can use map when you populate the array:

my @kkarray = map { basename($_) } glob("$kkLoc/*");
toolic
  • 57,801
  • 17
  • 75
  • 117
1

If you're only ever interested in the filenames within that directory, then just read the directory directly:

my $path = '.....';
opendir my $dir, $path or die "opendir($path): $!\n";
my @kkarray = sort grep !/^\.\.?$/, readdir $dir;
close $dir;
Dave Mitchell
  • 2,193
  • 1
  • 6
  • 7