In AppleScript it’s possible to get the the POSIX path of the folder the current script is located in using this line:
POSIX path of ((path to me as text) & "::")
Example result: /Users/aaron/Git/test/
What’s the JavaScript equivalent?
In AppleScript it’s possible to get the the POSIX path of the folder the current script is located in using this line:
POSIX path of ((path to me as text) & "::")
Example result: /Users/aaron/Git/test/
What’s the JavaScript equivalent?
Here's a way [NOTE: I NO LONGER RECOMMEND THIS METHOD. SEE EDIT, BELOW]:
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
app.doShellScript('dirname \'' + path + '\'') + '/';
note the single quotes surrounding path
to work with paths with spaces, etc., in the doShellScript
EDIT After being slapped on the hand by @foo for using a fairly unsafe path-quoting method, I'd like to amend this answer with:
ObjC.import("Cocoa");
app = Application.currentApplication();
app.includeStandardAdditions = true;
thePath = app.pathTo(this);
thePathStr = $.NSString.alloc.init;
thePathStr = $.NSString.alloc.initWithUTF8String(thePath);
thePathStrDir = (thePathStr.stringByDeletingLastPathComponent);
thePathStrDir.js + "/";
If you're going to use this string, of course, you still have to deal with whether or not it has questionable characters in it. But at least at this stage this is not an issue. This also demonstrates a few concepts available to the JXA user, like using the ObjC bridge and .js
to get the string "coerced" to a JavaScript string (from NSString).
Pure JXA code without ObjC involved:
App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')
var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()
So to sum up what I’m doing now, I’m answering my own question. Using @foo’s and @CRGreen’s excellent responses, I came up with the following:
ObjC.import('Foundation');
var app, path, dir;
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
dir = $.NSString.alloc.initWithUTF8String(path).stringByDeletingLastPathComponent.js + '/';
This is quite close to @CRGreen’s response, however, it’s a bit more terse and I’m importing Foundation
instead of Cocoa
. Plus, I’m declaring the variables I’m using to avoid accidental globals.
I think I found a simpler way to get the parent folder without invoking ObjC.
var app = Application.currentApplication();
app.includeStandardAdditions = true;
thePath = app.pathTo(this);
Path(thePath + '/../../')
Use -[NSString stringByDeletingLastPathComponent]
, which already knows how to remove the last path segment safely:
ObjC.import('Foundation')
path = ObjC.unwrap($(path).stringByDeletingLastPathComponent)
Alternatively, if you prefer the more dangerous life, you could use a regular expression to strip the last path segment from a POSIX path string. Off the top of my head (caveat emptor, etc):
path = path.replace(/\/[^\/]+\/*$/,'').replace(/^$/,'/')
(Note that the second replace()
is required to process paths with <2 parts correctly.)
To complement the helpful existing answers by providing self-contained utility functions:
// Return the POSIX path of the folder hosting this script / app.
// E.g., from within '/foo/bar.scpt', returns '/foo'.
function myPath() {
var app = Application.currentApplication(); app.includeStandardAdditions = true
return $(app.pathTo(this).toString()).stringByDeletingLastPathComponent.js
}
// Return the filename root (filename w/o extension) of this script / app.
// E.g., from within '/foo/bar.scpt', returns 'bar'.
// (Remove `.stringByDeletingPathExtension` if you want to retain the extension.)
function myName() {
var app = Application.currentApplication(); app.includeStandardAdditions = true
return $(app.pathTo(this).toString()).lastPathComponent.stringByDeletingPathExtension.js
}
Note: These functions make use of the shortcut syntax forms for the ObjC bridge ($(...)
for ObjC.wrap()
and .js
for ObjC.unwrap()
, and also take advantage of the fact that the Foundation
framework's symbols are available by default - see the OS X 10.10 JXA release notes.
It's easy to generalize these functions to provide the equivalents of the POSIX dirname
and basename
utilities:
// Returns the parent path of the specified filesystem path.
// A trailing '/' in the input path is ignored.
// Equivalent of the POSIX dirname utility.
// Examples:
// dirname('/foo/bar') // -> '/foo'
// dirname('/foo/bar/') // ditto
function dirname(path) {
return $(path.toString()).stringByDeletingLastPathComponent.js
}
// Returns the filename component of the specified filesystem path.
// A trailing '/' in the input path is ignored.
// If the optional <extToStrip> is specified:
// - If it it is a string, it is removed from the result, if it matches at
// the end (case-sensitively) - do include the '.'
// - Otherwise (Boolean or number), any truthy value causes any extension
// (suffix) present to be removed.
// Equivalent of the POSIX basename utility; the truthy semantics of the
// 2nd argument are an extension.
// Examples:
// basename('/foo/bar') // -> 'bar'
// basename('/foo/bar/') // ditto
// basename('/foo/bar.scpt', 1) // -> 'bar'
// basename('/foo/bar.scpt', '.scpt') // -> 'bar'
// basename('/foo/bar.jxa', '.scpt') // -> 'bar.jxa'
function basename(path, extToStrip) {
path = path.toString()
if (path[path.length-1] === '/') { path = path.slice(0, -1) }
if (typeof extToStrip === 'string') {
return path.slice(-extToStrip.length) === extToStrip ? $(path).lastPathComponent.js.slice(0, -extToStrip.length) : $(path).lastPathComponent.js
} else { // assumed to be numeric: if truthy, strip any extension
return extToStrip ? $(path).lastPathComponent.stringByDeletingPathExtension.js : $(path).lastPathComponent.js
}
}
Lots of interesting solutions above.
Here's mine, which does NOT require ObjC, and returns an object with properties likely to be needed.
'use strict';
var oScript = getScriptProp(this);
/*oScript Properties
Path
Name
ParentPath
Folder
*/
oScript.ParentPath;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function getScriptProp(pRefObject) {
var app = Application.currentApplication()
app.includeStandardAdditions = true
var pathScript = app.pathTo(pRefObject).toString();
var pathArr = pathScript.split("/")
var oScript = {
Path: pathScript,
Name: pathArr[pathArr.length - 1],
ParentPath: pathArr.slice(0, pathArr.length - 1).join("/"),
Folder: pathArr[pathArr.length - 2]
};
return oScript
}