[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Can "${x##*/}" be used to replace "$(basename "$x")"?
From: |
Lawrence Velázquez |
Subject: |
Re: Can "${x##*/}" be used to replace "$(basename "$x")"? |
Date: |
Mon, 17 Feb 2020 04:46:13 -0500 |
> On Feb 16, 2020, at 8:33 AM, Peng Yu <address@hidden> wrote:
>
> I think that "${x##*/}" is the same as "$(basename "$x")".
Be aware that $(basename "$x") produces an incorrect result if $x
ends in newlines, since command substitution discards them.
$ x=$'foo/bar\n'; printf '<%s>\n' "$(basename "$x")" "${x##*/}"
<bar>
<bar
>
This can be worked around, but that's not really what you're asking
about.
> But I am not sure if there is a corner case that they are not the
> same. Does anybody know if they are exactly the same semantically?
> Thanks.
Regardless of whether they always produce the same output (which
they don't), they can't be the same semantically. That parameter
expansion removes the longest prefix that ends with '/', while
`basename` is meant to output the nondirectory part of a pathname.
They usually do produce the same result, but that doesn't mean they
have the same *meaning*.
> On Feb 16, 2020, at 9:28 AM, Mike Jonkmans <address@hidden>
> wrote:
>
> For x=/ they differ.
Indeed.
$ x=/; printf '<%s>\n' "$(basename "$x")" "${x##*/}"
</>
<>
They also differ if the pathname ends in a slash.
$ x=foo/bar/; printf '<%s>\n' "$(basename "$x")" "${x##*/}"
<bar>
<>
Or if it consists entirely of slashes.
$ x=///////; printf '<%s>\n' "$(basename "$x")" "${x##*/}"
</>
<>
Or if it's a null string, and the `basename` implementation chooses
to output '.' for those.
$ x=; printf '<%s>\n' "$(basename "$x")" "${x##*/}"
<.>
<>
It'd be relatively straightforward to write a function based on
${x##*/} that handled edge cases. Take a look at POSIX
(https://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html)
to see what behaviors you'd have to implement.
vq