如何在 JavaScript 中获取当前脚本文件夹的 POSIX 路径用于自动化?
How to get POSIX path of the current script's folder in JavaScript for Automation?
在 AppleScript 中,可以使用此行获取当前脚本所在文件夹的 POSIX 路径:
POSIX path of ((path to me as text) & "::")
示例结果:/Users/aaron/Git/test/
JavaScript 等价物是多少?
这里有一个方法 [注意:我不再推荐这个方法。请参阅下面的编辑]:
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
app.doShellScript('dirname \'' + path + '\'') + '/';
请注意 path
周围的单引号,以便在 doShellScript
中使用带空格的路径等
编辑
在因使用相当不安全的路径引用方法而被@foo 掌掴后,我想修改此答案:
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 + "/";
如果你要使用这个字符串,当然,你仍然需要处理它是否有可疑字符。但至少在这个阶段这不是问题。这也演示了 JXA 用户可用的一些概念,例如使用 ObjC 桥和 .js
将字符串 "coerced" 转换为 JavaScript 字符串(来自 NSString)。
使用-[NSString stringByDeletingLastPathComponent]
,它已经知道如何安全地删除最后一个路径段:
ObjC.import('Foundation')
path = ObjC.unwrap($(path).stringByDeletingLastPathComponent)
或者,如果您喜欢更危险的生活,您可以使用正则表达式从 POSIX 路径字符串中删除最后一个路径段。从我的头顶(警告买者等):
path = path.replace(/\/[^\/]+\/*$/,'').replace(/^$/,'/')
(请注意,第二个 replace()
是正确处理具有 <2 个部分的路径所必需的。)
所以总结一下我现在正在做的事情,我正在回答我自己的问题。使用@foo 和@CRGreen 的出色回复,我得出以下结论:
ObjC.import('Foundation');
var app, path, dir;
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
dir = $.NSString.alloc.initWithUTF8String(path).stringByDeletingLastPathComponent.js + '/';
这与@CRGreen 的回复非常接近,但是,它更简洁一些,我正在导入 Foundation
而不是 Cocoa
。另外,我正在声明我使用的变量以避免意外的全局变量。
我想我找到了一种无需调用 ObjC 即可获取父文件夹的更简单方法。
var app = Application.currentApplication();
app.includeStandardAdditions = true;
thePath = app.pathTo(this);
Path(thePath + '/../../')
不涉及 ObjC 的纯 JXA 代码:
App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')
var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()
通过提供 独立的实用函数来补充有用的现有答案:
// 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
}
注意:这些函数使用 ObjC 桥的快捷语法形式($(...)
用于 ObjC.wrap()
,.js
用于 ObjC.unwrap()
,并利用 Foundation
框架的符号默认可用 - 请参阅 OS X 10.10 JXA release notes.
很容易概括这些函数以提供 POSIX dirname
和 basename
实用程序的 等价物:
// 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
}
}
上面有很多有趣的解决方案。
这是我的,它不需要 ObjC,并且 returns 具有可能需要的属性的对象。
'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
}
在 AppleScript 中,可以使用此行获取当前脚本所在文件夹的 POSIX 路径:
POSIX path of ((path to me as text) & "::")
示例结果:/Users/aaron/Git/test/
JavaScript 等价物是多少?
这里有一个方法 [注意:我不再推荐这个方法。请参阅下面的编辑]:
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
app.doShellScript('dirname \'' + path + '\'') + '/';
请注意 path
周围的单引号,以便在 doShellScript
编辑 在因使用相当不安全的路径引用方法而被@foo 掌掴后,我想修改此答案:
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 + "/";
如果你要使用这个字符串,当然,你仍然需要处理它是否有可疑字符。但至少在这个阶段这不是问题。这也演示了 JXA 用户可用的一些概念,例如使用 ObjC 桥和 .js
将字符串 "coerced" 转换为 JavaScript 字符串(来自 NSString)。
使用-[NSString stringByDeletingLastPathComponent]
,它已经知道如何安全地删除最后一个路径段:
ObjC.import('Foundation')
path = ObjC.unwrap($(path).stringByDeletingLastPathComponent)
或者,如果您喜欢更危险的生活,您可以使用正则表达式从 POSIX 路径字符串中删除最后一个路径段。从我的头顶(警告买者等):
path = path.replace(/\/[^\/]+\/*$/,'').replace(/^$/,'/')
(请注意,第二个 replace()
是正确处理具有 <2 个部分的路径所必需的。)
所以总结一下我现在正在做的事情,我正在回答我自己的问题。使用@foo 和@CRGreen 的出色回复,我得出以下结论:
ObjC.import('Foundation');
var app, path, dir;
app = Application.currentApplication();
app.includeStandardAdditions = true;
path = app.pathTo(this);
dir = $.NSString.alloc.initWithUTF8String(path).stringByDeletingLastPathComponent.js + '/';
这与@CRGreen 的回复非常接近,但是,它更简洁一些,我正在导入 Foundation
而不是 Cocoa
。另外,我正在声明我使用的变量以避免意外的全局变量。
我想我找到了一种无需调用 ObjC 即可获取父文件夹的更简单方法。
var app = Application.currentApplication();
app.includeStandardAdditions = true;
thePath = app.pathTo(this);
Path(thePath + '/../../')
不涉及 ObjC 的纯 JXA 代码:
App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')
var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()
通过提供 独立的实用函数来补充有用的现有答案:
// 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
}
注意:这些函数使用 ObjC 桥的快捷语法形式($(...)
用于 ObjC.wrap()
,.js
用于 ObjC.unwrap()
,并利用 Foundation
框架的符号默认可用 - 请参阅 OS X 10.10 JXA release notes.
很容易概括这些函数以提供 POSIX dirname
和 basename
实用程序的 等价物:
// 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
}
}
上面有很多有趣的解决方案。
这是我的,它不需要 ObjC,并且 returns 具有可能需要的属性的对象。
'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
}