How to go to alias from terminal?

By alias, I mean the folder shortcut created when you right-click a folder in Finder and select "Make Alias". I can traverse symbolic links in Terminal with cd, but it doesn't work on aliases: bash: cd: example-alias: Not a directory. Is it possible to change directory to an alias's destination in Terminal?


Solution 1:

To enable cd'ing into a folder alias I've found the following at Mac OS X Hints.

Compile the source code below with the following command:

gcc -o getTrueName -framework Carbon getTrueName.c

This will create the ‘getTrueName’ executable in the same directory as the source. You can add it to your PATH, or just copy it directly to /usr/bin or /usr/local/bin so it’s easy to access.

C source code for getTrueName (copy the text and save the file as getTrueName.c in your home directory):

// getTrueName.c
// 
// DESCRIPTION
//   Resolve HFS and HFS+ aliased files (and soft links), and return the
//   name of the "Original" or actual file. Directories have a "/"
//   appended. The error number returned is 255 on error, 0 if the file
//   was an alias, or 1 if the argument given was not an alias
// 
// BUILD INSTRUCTIONS
//   gcc-3.3 -o getTrueName -framework Carbon getTrueName.c 
//
//     Note: gcc version 4 reports the following warning
//     warning: pointer targets in passing argument 1 of 'FSPathMakeRef'
//       differ in signedness
//
// COPYRIGHT AND LICENSE
//   Copyright 2005 by Thos Davis. All rights reserved.
//   This program is free software; you can redistribute it and/or
//   modify it under the terms of the GNU General Public License as
//   published by the Free Software Foundation; either version 2 of the
//   License, or (at your option) any later version.
//
//   This program is distributed in the hope that it will be useful, but
//   WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//   General Public License for more details.
//
//   You should have received a copy of the GNU General Public
//   License along with this program; if not, write to the Free
//   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//   MA 02111-1307 USA


#include <Carbon/Carbon.h> 
#define MAX_PATH_SIZE 1024
#define CHECK(rc,check_value) if ((check_value) != noErr) exit((rc))

int main ( int argc, char * argv[] ) 
  { 
    FSRef               fsRef; 
    Boolean             targetIsFolder; 
    Boolean             wasAliased; 
    UInt8               targetPath[MAX_PATH_SIZE+1]; 
    char *              marker;

    // if there are no arguments, go away
    if (argc < 2 ) exit(255); 

    CHECK( 255,
      FSPathMakeRef( argv[1], &fsRef, NULL ));

    CHECK( 1,
      FSResolveAliasFile( &fsRef, TRUE, &targetIsFolder, &wasAliased));

    CHECK( 255,
      FSRefMakePath( &fsRef, targetPath, MAX_PATH_SIZE)); 

    marker = targetIsFolder ? "/" : "" ;
    printf( "%s%s\n", targetPath, marker ); 

    exit( 1 - wasAliased );
  }

Include the following in ~/.bash_profile or create a new file ~/.bash_profile with the following content:

function cd {
  if [ ${#1} == 0 ]; then
    builtin cd
  elif [ -d "${1}" ]; then
    builtin cd "${1}"
  elif [[ -f "${1}" || -L "${1}" ]]; then
    path=$(getTrueName "$1")
    builtin cd "$path"
  else
    builtin cd "${1}"
  fi
}

You probably have to restart Terminal to load your modified .bash_profile.

Tested in Yosemite 10.10.2 & gcc 4.2 (Xcode 6.2) and it works.

A similar approach is available at superuser.com

Solution 2:

I haven't tested the answer by @klanomath, but there used to be a Python library to get the target of an alias, but Carbon support was removed from the Apple frameworks. It can be done in Objective C see https://stackoverflow.com/a/21151368/838253.

The best bet is to use symlinks, but unfortunately Finder does not allow you to create these.

I have written an OS X Service which creates symlinks (which are supported by both Finder and Terminal). This runs the following bash script in a Finder workflow. (Unfortunately it doesn't seem to be possible to post Automator code in a readable format).

for f in "$@"
do
 fileSuffix="link"
 fileExists=`ls -d "$f $fileSuffix"`
 fileNumber=0

 until [ $fileExists=="" ]; do
  let fileNumber+=1
  fileSuffix="link $fileNumber"
  fileExists=`ls -d "$f $fileSuffix"`
 done

 echo "$f $fileSuffix"
 ln -s "$f" "$f $fileSuffix"
done

Solution 3:

Here is my take on this.

add and load this function to your .profile.

function cd  {
  thePath=`osascript <<EOD
set toPath to ""
tell application "Finder"
    set toPath to (POSIX file "$1") as alias
    set theKind to kind of toPath
    if theKind is "Alias" then
        set toPath to  ((original item of toPath) as alias)
    end if
end tell
return posix path of (toPath)
EOD`
  builtin cd "$thePath";
}

Update.

I used the builtin cd line shown in @klanomath answer which allows you to override the cd command. So we can now use:

cd /path/to/example-alias

or

cd /path/to/example

The function should return and cd to the original path of the aliases original or the normal path.

Solution 4:

While a symbolic link (UNIX alias) looks the same as a Finder alias inside Finder, they are two complete different types of aliases.

A symbolic link will only hold the path it leads to and will permanently or temporarily break if the resource is moved or on a disconnected drive or share respectively.

A Finder alias is technically an ordinary file with instructions for the Finder. The Finder can use this information to locate a moved target file/directory to a certain extent. If a target resource of an alias is on a mounted network share point, it also holds information of which Keychain item to use to log you in to the share point in order to open it.

So, unless you write a script or program to read out the Finder alias file, it will not use it as a directory, but as a file in Terminal.

Alternatively, you can remove the current Finder alias and create a symbolic link in its place. Command would be ln -s /path/to/original to create a symbolic link at the current directory. The path can be a full or relative path.

Solution 5:

  1. @markhunte's applescript worked, but there was a warning message: osascript[9807:7154723] CFURLGetFSRef was passed an URL which has no scheme (the URL will not work with other CFURL routines)

By the help of this tip, I modified @markunte's applescript to remove above warning message

  1. @markhunte's applescript is slightly slow because it always invokes the applescript. So following @klanomath's tip which is listed above, I modified the script to invoke the applescript only when target object is alias.
# Overriding cd to enable make alias available in CLI

function cd  {
    if [ ${#1} == 0 ]; then
        builtin cd
    elif [ -d "${1}" ]; then
        builtin cd "${1}"
    elif [[ -f "${1}" || -L "${1}" ]]; then
        thePath=`osascript <<EOD
set toPath to ""
tell application "Finder"
    set toPath to (POSIX file ((do shell script "pwd")&"/$1")) as alias
    set theKind to kind of toPath
    if theKind is "Alias" then
        set toPath to  ((original item of toPath) as alias)
    end if
end tell
return posix path of (toPath)
EOD`
        builtin cd "$thePath";
    else
        builtin cd "${1}"
    fi
}