60

我只是想在我的 applescript 的整个生命周期中记录对象的状态。在其他语言中,对象的 toString() 方法将呈现等效的文本,我可以使用它们。在 AppleScript 中,情况似乎并非如此。

convert applescript object to string (similar to toString)

将查找器对象(及其属性)输出到 AppleScript 编辑器的“结果”窗口,但前提是它是最后执行的语句。

如果我有一个 trace() 语句(用于记录目的的消息):

on trace(message)
do shell script "cat >>~/log/applescript.txt <<END_OF_THE_LOG
" & (message as text) & "
END_OF_THE_LOG"
end trace

并尝试记录相同的对象,我得到

Can’t make properties of application "Finder" into type text.

我愿意接受更好的登录控制台的方法,但想了解如何在脚本中间编写对象的属性(如 AppleScript 编辑器所做的)以测试任何一种方式。

4

8 回答 8

44

AppleScript 并不容易:

  • log 在 AppleScript Editor 中运行或通过osascriptstderr在这种情况下)运行时记录 - 在其他情况下输出将丢失,例如当应用程序运行具有NSAppleScriptCocoa 类的脚本时。

  • log只接受一个论点;虽然它确实接受任何对象类型,但它并不容易获得非内置类型的有意义表示:log me例如,尝试获取有关脚本本身的信息;经常,log (get properties of <someObj>)必须用于获取有意义的信息;请注意繁琐的语法,这是必需的,因为仅使用log properties of <someObj>通常仅打印引用表单的名称而不是其指向的属性(例如,无log properties of me用地输出 just (*properties*))。

  • 一般来说,AppleScript 很难获得非内置类型对象的有意义的文本表示:(<someObj> as text与: 相同<someObj> as string)令人讨厌的中断- 引发运行时错误 - 对于此类对象;试试me as text

以下是解决这些问题的辅助子程序

  • dlog()是一个子例程,它将任何对象的有意义的文本表示与基于全局配置变量的写入多个日志目标(包括系统日志和文件)的能力相结合。
  • toString()(有效嵌入dlog())是一个子例程,它接受任何类型的单个对象并从中派生出有意义的文本表示。

向@1.61803 致敬;他的回答为实现各种日志目标提供了指导。

例子:

  # Setup: Log to syslog and a file in the home dir.
  #        Other targets supported: "log", "alert"
  #        Set to {} to suppress logging.
set DLOG_TARGETS to { "syslog", "~/as.log" } 
  # Log properties of the front window of frontmost application.
dlog(front window of application (path to frontmost application as text))
  # Log properties of own front window; note the *list* syntax for multiple args.
dlog({"my front window: ", front window})

  # Get properties of the running script as string.
toString(me) # ->, e.g.: [script name="sandbox"] {selection:insertion point after character 2475 of text of document "sandbox2.scpt", frontmost:true, class:application, name:"AppleScript Editor", version:"2.6"}

有关详细信息,请参阅每个子例程上方的源代码注释。


dlog() 源代码

    # Logs a text representation of the specified object or objects, which may be of any type, typically for debugging.
    # Works hard to find a meaningful text representation of each object.
    # SYNOPSIS
    #   dlog(anyObjOrListOfObjects)
    # USE EXAMPLES
    #   dlog("before")  # single object
    #     dlog({ "front window: ", front window }) # list of objects
    # SETUP
    #   At the top of your script, define global variable DLOG_TARGETS and set it to a *list* of targets (even if you only have 1 target).
    #     set DLOG_TARGETS to {} # must be a list with any combination of: "log", "syslog", "alert", <posixFilePath>
    #   An *empty* list means that logging should be *disabled*.
    #   If you specify a POSIX file path, the file will be *appended* to; variable references in the path
    #   are allowed, and as a courtesy the path may start with "~" to refer to your home dir.
    #   Caveat: while you can *remove* the variable definition to disable logging, you'll take an additional performance hit.
    # SETUP EXAMPLES
    #    For instance, to use both AppleScript's log command *and* display a GUI alert, use:
    #       set DLOG_TARGETS to { "log", "alert" }
    # Note: 
    #   - Since the subroutine is still called even when DLOG_TARGETS is an empty list, 
    #     you pay a performancy penalty for leaving dlog() calls in your code.
    #   - Unlike with the built-in log() method, you MUST use parentheses around the parameter.
    #   - To specify more than one object, pass a *list*. Note that while you could try to synthesize a single
    #     output string by concatenation yourself, you'd lose the benefit of this subroutine's ability to derive
    #     readable text representations even of objects that can't simply be converted with `as text`.
    on dlog(anyObjOrListOfObjects)
        global DLOG_TARGETS
        try
            if length of DLOG_TARGETS is 0 then return
        on error
            return
        end try
        # The following tries hard to derive a readable representation from the input object(s).
        if class of anyObjOrListOfObjects is not list then set anyObjOrListOfObjects to {anyObjOrListOfObjects}
        local lst, i, txt, errMsg, orgTids, oName, oId, prefix, logTarget, txtCombined, prefixTime, prefixDateTime
        set lst to {}
        repeat with anyObj in anyObjOrListOfObjects
            set txt to ""
            repeat with i from 1 to 2
                try
                    if i is 1 then
                        if class of anyObj is list then
                            set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}} # '
                            set txt to ("{" & anyObj as string) & "}"
                            set AppleScript's text item delimiters to orgTids # '
                        else
                            set txt to anyObj as string
                        end if
                    else
                        set txt to properties of anyObj as string
                    end if
                on error errMsg
                    # Trick for records and record-*like* objects:
                    # We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
                    try
                        set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
                    end try
                end try
                if txt is not "" then exit repeat
            end repeat
            set prefix to ""
            if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
                set prefix to "[" & class of anyObj
                set oName to ""
                set oId to ""
                try
                    set oName to name of anyObj
                    if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
                end try
                try
                    set oId to id of anyObj
                    if oId is not missing value then set prefix to prefix & " id=" & oId
                end try
                set prefix to prefix & "] "
                set txt to prefix & txt
            end if
            set lst to lst & txt
        end repeat
        set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {" "}} # '
        set txtCombined to lst as string
        set prefixTime to "[" & time string of (current date) & "] "
        set prefixDateTime to "[" & short date string of (current date) & " " & text 2 thru -1 of prefixTime
        set AppleScript's text item delimiters to orgTids # '
        # Log the result to every target specified.
        repeat with logTarget in DLOG_TARGETS
            if contents of logTarget is "log" then
                log prefixTime & txtCombined
            else if contents of logTarget is "alert" then
                display alert prefixTime & txtCombined
            else if contents of logTarget is "syslog" then
                do shell script "logger -t " & quoted form of ("AS: " & (name of me)) & " " & quoted form of txtCombined
            else # assumed to be a POSIX file path to *append* to.
                set fpath to contents of logTarget
                if fpath starts with "~/" then set fpath to "$HOME/" & text 3 thru -1 of fpath
                do shell script "printf '%s\\n' " & quoted form of (prefixDateTime & txtCombined) & " >> \"" & fpath & "\""
            end if
        end repeat
    end dlog

toString() 源代码

    # Converts the specified object - which may be of any type - into a string representation for logging/debugging.
    # Tries hard to find a readable representation - sadly, simple conversion with `as text` mostly doesn't work with non-primitive types.
    # An attempt is made to list the properties of non-primitive types (does not always work), and the result is prefixed with the type (class) name
    # and, if present, the object's name and ID.
    # EXAMPLE
    #       toString(path to desktop)  # -> "[alias] Macintosh HD:Users:mklement:Desktop:"
    # To test this subroutine and see the various representations, use the following:
    #   repeat with elem in {42, 3.14, "two", true, (current date), {"one", "two", "three"}, {one:1, two:"deux", three:false}, missing value, me,  path to desktop, front window of application (path to frontmost application as text)}
    #       log my toString(contents of elem)
    #   end repeat
    on toString(anyObj)
        local i, txt, errMsg, orgTids, oName, oId, prefix
        set txt to ""
        repeat with i from 1 to 2
            try
                if i is 1 then
                    if class of anyObj is list then
                        set {orgTids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {", "}}
                        set txt to ("{" & anyObj as string) & "}"
                        set AppleScript's text item delimiters to orgTids # '
                    else
                        set txt to anyObj as string
                    end if
                else
                    set txt to properties of anyObj as string
                end if
            on error errMsg
                # Trick for records and record-*like* objects:
                # We exploit the fact that the error message contains the desired string representation of the record, so we extract it from there. This (still) works as of AS 2.3 (OS X 10.9).
                try
                    set txt to do shell script "egrep -o '\\{.*\\}' <<< " & quoted form of errMsg
                end try
            end try
            if txt is not "" then exit repeat
        end repeat
        set prefix to ""
        if class of anyObj is not in {text, integer, real, boolean, date, list, record} and anyObj is not missing value then
            set prefix to "[" & class of anyObj
            set oName to ""
            set oId to ""
            try
                set oName to name of anyObj
                if oName is not missing value then set prefix to prefix & " name=\"" & oName & "\""
            end try
            try
                set oId to id of anyObj
                if oId is not missing value then set prefix to prefix & " id=" & oId
            end try
            set prefix to prefix & "] "
        end if
        return prefix & txt
    end toString
于 2014-01-24T19:56:24.703 回答
41

只需使用logAppleScript 编辑器中的语句。当您在 Applescript 编辑器中查看结果时,在窗口底部按“事件”按钮。通常按下“结果”按钮,然后您只会看到您提到的最后一条语句的结果。因此,将按钮更改为“事件”。这将向您显示脚本运行时发生的所有事情,以及log您在整个代码中放置的所有语句。请注意,log语句不必是文本。您可以记录任何对象。

这是调试脚本并查看发生了什么的最佳方式。作为一个例子,试试这个并查看“事件”。如果您查看事件,实际上认为您不需要很多log语句,因为所有内容都已记录!

set someFolder to path to desktop
log someFolder

tell application "Finder"
    set someItem to first item of someFolder
    log someItem

    set itemProps to properties of someItem
    log itemProps
end tell
于 2012-11-30T22:30:35.717 回答
13

尝试以下任何方法:

# echo to file
do shell script "echo " & quoted form of (myObj as string) & ¬
    " > ~/Desktop/as_debug.txt"

# write to file
set myFile to open for access (path to desktop as text) & ¬
    "as_debug2.txt" with write permission
write myObj to myFile
close access myFile

# log to syslog
do shell script "logger -t 'AS DEBUG' " & myObj

# show dialog
display dialog "ERROR: " & myObj

如果您尝试记录的不是文本,您可以尝试:

quoted form of (myObj as string)
于 2014-01-23T13:37:01.133 回答
2

以下是控制台日志的示例:

set my_int to 9945
log my_int
set my_srt to "Hamza"
log my_srt 
set my_array ["Apple","Mango","Banana","Gava"]
log my_array
set my_obj to {"Ali"} as string
log my_obj
于 2018-12-27T16:23:09.523 回答
1
do shell script "echo '" & (current date) & ": Found " & Thisfilename & "' >> ~/logs/MyGreatAppleScript.log"
于 2014-06-28T17:31:54.147 回答
1

类似于toString()...

on TextOf(aVariable)
    try
        return "" & aVariable
    on error errm
        if errm begins with "Can’t make " ¬
       and errm ends with " into type Unicode text." then ¬
            return text 12 through -25 of errm
        return "item of class " & (class of aVariable) & return & errm
    end try
end TextOf
于 2018-05-03T00:01:09.000 回答
0

了解您的价值观的最简单方法-

display dialog "my variable: " & myVariableName
于 2019-03-22T06:14:23.020 回答
0

对于运行时间较长且我不看屏幕的脚本,我喜欢让 applescript 大声说出它在做什么。

IE。

say “This is a log statement.”

如果在一个tell语句中:

tell me to say “This is a log statement.”
于 2021-03-20T04:27:33.263 回答