How to parse full path apart from filename?

I can get the relative path and filename of the executable with:

print "Relative path and filename = ", PROGRAM_NAME, "\n"

And I can get the full path and filename of the executable with:

print "Full path, including filename = ", Path[PROGRAM_NAME].expand, "\n"

And I can get just the filename of the executable with:

print "Filename = ", Path[PROGRAM_NAME].basename, "\n"

But without doing string parsing, I can not for the life of me figure out how to get just the path, without the filename of the executable.

Surely it’s only because I’m not enough of a programmer to comprehend the documentation?

Anyone know the magic incantation I need?

Thanks!

SOLVED.

print "Full path, excluding filename = ", Path[PROGRAM_NAME].expand.dirname, "\n"

Thanks!

Path#dirname is correct to get the path of the parent directory.

However, Path[PROGRAM_NAME].expand only works correctly when the program is executed via a relative path.
PROGRAM_NAME is whatever the user typed into their shell to run the program. If it’s a path relative to the current directory, Path#expand works fine (and also if it’s an absolute path, of course).
If however it’s only a name that’s resolved in $PATH, this mechanism would be broken.

You might want to use Process.executable_path instead.

I appreciate your response, but I fear you expect more programming/Crystal knowledge from me than I possess. This code:

puts Path#dirname

just outputs the word ā€œPathā€ for me, and this code:

puts Process.executable_path

outputs the entire path with filename, and this path:

puts Process.executable_path.dirname

generates an error from the compiler:

In first_steps.cr:8:30

8 | puts Process.executable_path.dirname
^------
Error: undefined method ā€˜dirname’ for Nil (compile-time type is (String | Nil))

Reference the official doc

Returns an absolute path to the executable file of the currently running program. This is in opposition to PROGRAM_NAME which may be a relative or absolute path, just the executable file name or a symlink.

The executable path will be canonicalized (all symlinks and relative paths will be expanded).

Returns nil if the file can’t be found.

Although, i really don’t know why THE fILE CAN'T BE FOUND in this case, maybe core member can give some detailed explain.

The workaround is: puts Process.executable_path.as(String).dirname

Path#dirname is just a convention to colloquially reference a method. It’s not intended as source code.

A simple reason for this would be that the executable file which spawned the current process has since been removed.
For example demonstrated by the following program:

if path = Process.executable_path
  File.delete(path)
end

Process.executable_path # => nil

This is just exposing a feature of the operating system and there might be all kinds of other reasons why the OS cannot report the path name or why it’s not available to the current process.

1 Like