Take the 2-minute tour ×
Ask Different is a question and answer site for power users of Apple hardware and software. It's 100% free, no registration required.

I am writing a generic script that can get passed both absolute and relative (to the current working dir) paths to existing files.

I need a fail-safe way to turn all those passed paths into absolute paths because I need to pass the paths to the "open" command, which in won't pass the current directory to the launched app.

One idea I had is to check if the path starts with a "/", and if not, then I'd prepend the current working dir's path to it.

However, I wonder if there's a smarter solution to this. Also, as I'm quite inexperienced with shell scripting and related tools, I don't even know how to test for a variable's value to start with "/". I'm looking for a portable solution to run on multiple Mac, so installing extra tools or configuration would be less than ideal.

Can someone suggest a standard script using only shipping tools that takes a variable (let's call it $path) and turns it into a absolute path if it's not already absolute?

share|improve this question
    
What language(s) do you prefer for your script? Perhaps that script has a function to call for handling path expansion. –  bmike Feb 14 '13 at 16:22
    
A simple "sh" script is fine, and it should only use features that are available on any recent OS X, i.e. installing extra tools is not an option. Basically, the scripts gets the file ref passed as an argument ($1) and I want to turn it into an abs path I can pass to the "open" command. –  Thomas Tempelmann Feb 14 '13 at 17:16
    
I like @Lauri Ranta's take on rolling your own solution. It's quite powerful. –  bmike Feb 14 '13 at 17:18
    
Are you sure that open does not keep the calling processes current directory - man open - the examples explicitly say current working directory. (if not I think Apple needs a bug report) –  Mark Feb 14 '13 at 18:40
    
@Mark, it's my own app that is launched by the open cmd and then tries to open the passed files, so it may also be that I did something wrong there. –  Thomas Tempelmann Feb 15 '13 at 18:27
add comment

3 Answers

One option would be to install coreutils and use greadlink -f. It resolves symlinks and it works with /Foo/ or ~/foo.txt if they don't exist, but not with /Foo/foo.txt if /Foo/ doesn't exist.

$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$ 

This doesn't resolve symlinks, and it doesn't work with /Foo/foo.txt either.

abspath() {
  if [ -d "$1" ]; then
    ( cd "$1"; dirs -l +0 )
  else
    ( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
  fi
}

abspath /etc # /etc
abspath /Foo/foo.txt # doesn't work
abspath /Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store

dirs -l performs tilde expansion. dirs +0 prints only the top directory if there are other directories in the stack. You could also replace the subshells with something like old="$PWD" ... cd "$old".

Ruby's expand_path works with all paths that don't exist, but it doesn't resolve symlinks.

$ ruby -e 'print File.expand_path ARGV[0]' ~/aa/bb
/Users/lauri/aa/bb$ 
share|improve this answer
    
I saw your post already on the older question that bmike linked to. I've now taken mschrag's version, though, and that satisfies my needs well. –  Thomas Tempelmann Feb 14 '13 at 17:13
add comment

I'm not sure if this answer will be comprehensive enough for your needs, but this is what I would do…

--DISCLAIMER: I haven't tested this in SH/BASH/Anything so just use this as a framework please. Feel free to edit the question after you've got it working!--

You can test if the supplied script argument begins with a character using something like if [[ $a == "/*" ]].

Since all relative paths carry with them the assumption that the working path is the parent directory, if you know the path is not already absolute you can use pwd, assuming the script or parent process hasn't changed the working directory.

If the issue of the working directory changing is significant, you'll have to use a function like find.


Some additional notes that might get you on the right path to solving your issue: http://unix.stackexchange.com/questions/6435/how-to-check-if-pwd-is-a-subdirectory-of-a-given-path

http://www.unix.com/shell-programming-scripting/36200-getting-full-path-relative-path.html

http://stackoverflow.com/questions/2172352/in-bash-how-can-i-check-if-a-string-begins-with-some-value

Hope this puts you in the right direction!

share|improve this answer
    
Yes, thanks for the test for the leading slash. That'll be enough for me to make my own script working. I only now realize that I was asking the question in a more general way, and so I'll see if someone come up with a solution that covers all cases before I mark the best answer. –  Thomas Tempelmann Feb 14 '13 at 16:21
    
Don't use quotes around /* in the pattern match -- within quotes, it treats the asterisk literally rather than as a match-all wildcard. –  Gordon Davisson Feb 14 '13 at 17:16
add comment

No - a path is just a string and you have to parse it to decide if it's absolute or relative to $PWD or ~

See these for more context in case my answer is too short.

share|improve this answer
    
Okay, I forgot about the cases where the path could start with "~". In my case, I know I won't run into this case, but for the sake of a helpful general answer I'll keep waiting for someone who has a overall solution. Supposedly, the "realpath" command can do that, which is available on Linux, it appears, but not on OSX. –  Thomas Tempelmann Feb 14 '13 at 16:18
    
Both realpath and readlink do not handle path expansion on OS X. Unless you find a package in homebrew or some other open source package to compile and call, you'll want to handle it in your shell script or do your processing on Linux. –  bmike Feb 14 '13 at 16:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.