help-bash
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]