【问题标题】:How to log objects to a console with AppleScript如何使用 AppleScript 将对象记录到控制台
【发布时间】:2012-11-19 03:42:14
【问题描述】:

我只是想在我的 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 编辑器所做的那样)以测试任何一种方式。

【问题讨论】:

  • 很好的问题,但我不明白第一个代码 sn-p:convert applescript object to string (similar to toString)。你在那里做什么?这与 Finder 有什么关系?

标签: applescript


【解决方案1】:

只需在 AppleScript 编辑器中使用 log 语句。当您在 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

【讨论】:

  • 这不适用于从其他地方执行的脚本,例如执行脚本的 Mail.app 规则。在 Mac OS X 10.8 上,我曾经做 -> 做 shell 脚本“logger '”& oneText &“'”。我不知道这将如何与沙盒一起使用。
【解决方案2】:

尝试以下任一方法:

# 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)

【讨论】:

  • +1 - 方便的东西;不幸的是,使用as string 会破坏非内置类型;看我的回答。
【解决方案3】:

AppleScript 并不容易:

  • log 在 AppleScript 编辑器中运行或通过 osascript 运行时(在这种情况下为 stderr)记录 - 在其他情况下输出将丢失,例如就像应用程序使用 NSAppleScript Cocoa 类运行脚本一样。

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

  • 1234563引发运行时错误 - 对于此类对象;试试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"}

详情请参见每个子例程上方的源代码 cmets。


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

【讨论】:

  • SO 使用的上下文文本着色显然不是 Applescript 精明的。未来会发生这种情况吗?
  • @wide_eyed_pupil:好问题;刚刚改进了这篇文章的着色。这是(有点麻烦的)技巧:在每个代码块之前加上&lt;!-- language: lang-applescript --&gt;,然后是一个空行。然后在任何包含奇数个单引号(')的行末尾添加# ',例如上面的set AppleScript's text item delimiters ...。最后,对 cme​​ts 使用 #,而不是 --。注意lang-applescript 不被官方支持;它似乎通过回退到不同的语法来工作,但如果你添加单引号技巧,它似乎工作得相当好。
  • 谢谢你 mklement0 现在有办法在 SO 中为评论/页面/问题/答案添加书签吗?
  • @wide_eyed_pupil:您可以收藏问题(单击左侧的星形图标) - 这将使它们显示在您的个人资料页面的“收藏夹”选项卡中。您可以使用普通浏览器书签链接到整个问题页面或单个答案 - 无法直接链接到我知道的评论。对于整个问题,使用它下方的“分享”链接会比使用常规 URL 提供更短的链接(对于单独的答案,这是获得链接的唯一方法)。
  • @wide_eyed_pupil 实际上,如果您使用浏览器的检查器,您可以找到评论的 html 元素的 id,将其添加到问题的 url 将允许您直接创建指向评论:stackoverflow.com/questions/13653358/…
【解决方案4】:
do shell script "echo '" & (current date) & ": Found " & Thisfilename & "' >> ~/logs/MyGreatAppleScript.log"

【讨论】:

    【解决方案5】:

    类似于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
    

    【讨论】:

      【解决方案6】:

      以下是控制台日志示例:

      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
      

      【讨论】:

        【解决方案7】:

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

        display dialog "my variable: " & myVariableName
        

        【讨论】:

        • 每次运行脚本时都必须关闭对话框很容易吗?不在我的书中
        • 帮助了我 - 很好,很直接??
        【解决方案8】:

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

        即。

        say “This is a log statement.”
        

        如果在一个tell语句中:

        tell me to say “This is a log statement.”
        

        【讨论】:

          猜你喜欢
          • 2020-07-30
          • 1970-01-01
          • 1970-01-01
          • 2017-08-22
          • 1970-01-01
          • 2018-10-01
          • 2015-04-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多