Comments (16)
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.
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.
I can't reproduce an output in where they differ now. 👍
from pure-bash-bible.
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.
Working on a fix. Great catch.
from pure-bash-bible.
Fixed.
dirname() {
# Usage: dirname "path"
dir=${1%%/}
[[ $dir ]] || dir=//
[[ $dir == */* ]] || dir=.
printf '%s\n' "${dir%/*}"
}
from pure-bash-bible.
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.
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.
For something/
it just strips the ending slash rather than returning dot.
from pure-bash-bible.
Here we go again:
dirname() {
# Usage: dirname "path"
dir=${1%%/}
[[ "${dir##*/*}" ]] && dir=.
dir=${dir%/*}
printf '%s\n' "${dir:-/}"
}
from pure-bash-bible.
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.
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.
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.
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.
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.
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)
- Alternative to dos2unix
- Inaccurate Caveat for `split()`
- Much More Compatible `reverse_array()`
- Splitting a string on a delimiter HOT 1
- Bash HOT 1
- Pedantic use of ':' "in place of a temporary variable." HOT 1
- shift at least... HOT 2
- basename with one argument fails with set -u HOT 1
- read, store, write a file including nulls
- Is this project active? HOT 4
- Typo in function date HOT 1
- Using coproc with read in non-interactive shells for sleep alternative
- Bash
- [[ ' aaaa' =~ a* ]] && echo ${BASH_REMATCH[0]} || echo no HOT 8
- for loop HOT 3
- wierd if statement HOT 1
- Is the Repository Dead? HOT 1
- Bash HOT 1
- bash read multi-line string with Process Substitution HOT 1
- UPPER CASE %02X instead of x
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pure-bash-bible.