If there is a topic in code exchange about basename there should be one about dirname as well.
Dirname as it works in the shell; tried to simulate as much as much code as in the dirname command line utility. Still it is about 50 times faster as in a single do shell script command.
dirName("/") --result : /
dirName("/a") --result : /
dirName("/a/b") --result : /a
dirName("/a/b/") --result : /a
dirName("/a/b//") --result : /a
dirName("/a/b/c") --result : /a/b
dirName("/a/b/c/") --result : /a/b
dirName("/a/b//c") --result : /a/b
dirName("/a//b/c") --result : /a//b; this is correct
on dirName(__n)
script s
property AoB : missing value
end script
if __n's length < 2 then return __n
set s's AoB to id of __n
repeat until last item of s's AoB is not 47
set s's AoB to items 1 thru -2 of s's AoB
end repeat
set {p, b} to {{}, {}}
repeat with char in s's AoB
set end of b to contents of char
if contents of char = 47 then
set p to p & b
set b to {}
end if
end repeat
if p = {47} then return string id p
repeat until last item of p is not 47
set p to items 1 thru -2 of p
end repeat
return string id p
end dirName
update: Adjusted the comments; they match the result.
The results are not exactly the same then that of the shell dirname command.
dirname removes all trailing slashes in the result, except only a slash is the result. The second difference is if you call dirname with only a file name, the result would be the current directory “.”
As an example:
dirname “/” → /
dirname “a” → .
dirname “/a/b/” → /a
I tried a quick and dirty solution for that without considering performance. Maybe splitting the text with AppleScript’s text item delimiters can speed up things.
on dirname(s)
set i to number of characters of s
set x to i
-- remove trailing slashes
repeat while x > 1
if character x of s = "/" then
set x to x - 1
else
exit repeat
end if
end repeat
-- remove filename
repeat while x > 0
if character x of s is not "/" then
set x to x - 1
else
exit repeat
end if
end repeat
-- remove trailing slashes
repeat while x > 1
if character x of s = "/" then
set x to x - 1
else
exit repeat
end if
end repeat
if x is 0 then
return "."
else
return text 1 thru x of s
end if
end dirname
{dirname("/a/b/c"), dirname("."), dirname("a//b"), dirname("/")} -- /a/b, . a, /
Happy scripting,
Stefan
You haven’t tested the code did you ? My comments aren’t exactly the same as the result, sorry for that. There are no trailing slashes in my example code either (meanwhile I adjusted the comments of my previous post). For pwd, I didn’t support it because AppleScript doesn’t have such thing so I thought it isn’t needed
Yep, you’re right, I just tested the last ones which results where like the comments…:rolleyes:
Nevertheless I think you should consider to return the current directory even if you have no use for it now. There might be cases when this comes handy - for example analysing an installer log file.
Slightly faster than DJ’s, about the same as Stefan’s (on my machine):
dirName("/") --result : /
dirName("/a") --result : /
dirName("/a/b") --result : /a
dirName("/a/b/") --result : /a
dirName("/a/b//") --result : /a
dirName("/a/b/c") --result : /a/b
dirName("/a/b/c/") --result : /a/b
dirName("/a/b//c") --result : /a/b
dirName("/a//b/c") --result : /a//b; this is correct
dirName("aardvark/") -- result : .
on dirName(__n)
set namesFound to 0
if ((count __n) > 0) then
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "/"
set TIs to __n's text items
repeat with i from (count TIs) to 1 by -1
if ((count item i of TIs) > 0) then
set namesFound to namesFound + 1
if (namesFound is 2) then exit repeat
end if
end repeat
set dn to text 1 thru text item i of __n
set AppleScript's text item delimiters to astid
end if
if ((namesFound < 2) and (__n does not start with "/")) then set dn to "."
return dn
end dirName
Nigel, I like that one. I assume it will be even faster if you play with real paths which usually will have longer filenames than just one character.