GithubHelp home page GithubHelp logo

Comments (16)

calimeroteknik avatar calimeroteknik commented on June 4, 2024 1

The direct implementation looks standard-conformant to me indeed. (beyond reasonable doubt although without machine-assisted checking)

I did not verify the second implementation; unlike basename the problem is a little bit too large for me to mentally check that it the second implementation is equivalent to the first. We must recognize our limits as programmers: validating this one without machine assistance is most likely out of my league…

Playing it heuristic-style, if this codegolf passed all tests first time, it's not proof but it's an encouraging sign.

Historical anecdote: hidden files in UNIX were "invented" by accident due to a subtle bug in the, I'd say "codegolf" implementation of ls, where it was supposed to ignore the special directories . and .. but in fact ignored all filenames starting in a dot. Oops… But this was (ab?)used and became the standard.

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Great catch.

This passes your above tests:

dirname() {
    # Usage: dirname "path"
    dir=${1%%/}

    [[ $dir == */* ]] || dir=.

    printf '%s\n' "${dir%/*}"
}

I'll keep digging to see if there are any other cases in which it fails. 👍

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

I can't reproduce an output in where they differ now. 👍

from pure-bash-bible.

calimeroteknik avatar calimeroteknik commented on June 4, 2024

The fix for the corner cases I mentioned introduced a regression:

~ $ dirname_pbb() {
    # Usage: dirname "path"
    dir=${1%%/}

    [[ $dir == */* ]] || dir=.

    printf '%s\n' "${dir%/*}"
}
~ $ dirname_pbb /
.
~ $ dirname /
/

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Working on a fix. Great catch.

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Fixed.

dirname() {
    # Usage: dirname "path"
    dir=${1%%/}

    [[ $dir ]] || dir=//
    [[ $dir == */* ]] || dir=.

    printf '%s\n' "${dir%/*}"
}

from pure-bash-bible.

calimeroteknik avatar calimeroteknik commented on June 4, 2024

Tests find errors, but unfortunately do not prove correctness:

~ $ dirname_pbb() {
    # Usage: dirname "path"
    dir=${1%%/}

    [[ $dir ]] || dir=//
    [[ $dir == */* ]] || dir=.

    printf '%s\n' "${dir%/*}"
}
~ $ dirname_pbb /foo

~ $ dirname /foo
/

I believe that this would warrant formal verification rather than testing, because it seems tricky.

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Try this one:

dirname() {
    # Usage: dirname "path"
    dir=${1%%/}
    dir=${dir%/*}

    [[ $1 == */* ]] || dir=.

    printf '%s\n' "${dir:-/}"
}

It passes my ever growing list of testcases. Either way, it's a lot more correct than what was previously in the book. :)

from pure-bash-bible.

calimeroteknik avatar calimeroteknik commented on June 4, 2024

For something/ it just strips the ending slash rather than returning dot.

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Here we go again:

dirname() {
    # Usage: dirname "path"
    dir=${1%%/}
    [[ "${dir##*/*}" ]] && dir=.
    dir=${dir%/*}

    printf '%s\n' "${dir:-/}"
}

from pure-bash-bible.

calimeroteknik avatar calimeroteknik commented on June 4, 2024

To still find problems we now need to go into non-normalised paths, for example, something//

I'm not even sure that the original dirname(1) is actually POSIX-conformant by all accounts anyway, so this might end up being a bug-for-bug reimplementation of the GNU coreutils version: I assume that the standard would be a better reference past this point.

This being said, dirname(1) from the GNU coreutils acts as if it normalised all but the prefix slashes (edit: unless the prefix slashes are the trailing slashes); I assume they considered it safer to keep them as-is, seeing as on some systems //something is not the same thing as /something.

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

I'm testing against busybox dirname as I don't use glibc/GNU coreutils. I'm not sure if busybox dirname is more POSIX compliant or not.

from pure-bash-bible.

calimeroteknik avatar calimeroteknik commented on June 4, 2024

Yes, as noted in my previous comment non-normalised paths are still problematic… but at this point, isn't it safer to just read POSIX rather than retro-engineer busybox through test cases?

The standard describes an algorithm:
https://pubs.opengroup.org/onlinepubs/009695399/utilities/dirname.html

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Here's an implementation of the algorithm described in the standard:

dirname() {
    # Usage: dirname "path"
    local tmp=${1:-.}

    [[ $tmp != *[!/]* ]] && {
        printf '/\n'
        return
    }

    tmp=${tmp%%"${tmp##*[!/]}"}

    [[ $tmp != */* ]] && {
        printf '.\n'
        return
    }

    tmp=${tmp%/*}
    tmp=${tmp%%"${tmp##*[!/]}"}

    printf '%s\n' "${tmp:-/}"
}

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

Here's another implementation which also passes all of my tests. It's also effectively the same algorithm as above.

dirname() {
  # Usage: dirname "path"
  local tmp=${1:-.}

  tmp=${tmp%%"${tmp##*[!/]}"}

  [[ ${tmp##*/*} ]] && tmp=.

  tmp=${tmp%/*}
  tmp=${tmp%%"${tmp##*[!/]}"}

  printf '%s\n' "${tmp:-/}"
}

from pure-bash-bible.

dylanaraps avatar dylanaraps commented on June 4, 2024

I'll push the direct implementation to the bible. 👍

Regardless of whether or not it is 100% compatible with the standard, this version is a lot "more" compatible with it. At some point I'll set up some proper tests so I can "safely" say "POSIX conformant".

Historical anecdote: hidden files in UNIX were "invented" by accident due to a subtle bug in the, I'd say "codegolf" implementation of ls, where it was supposed to ignore the special directories . and .. but in fact ignored all filenames starting in a dot. Oops… But this was (ab?)used and became the standard.

I knew this! Very interesting fact.

Thank you for all the help thus far!

from pure-bash-bible.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.