【问题标题】:VBA Shell function in Office 2011 for MacOffice 2011 for Mac 中的 VBA Shell 函数
【发布时间】:2011-09-02 11:14:38
【问题描述】:

我正在尝试从 Word 2011 for Mac 中的 VBA 宏启动 shell 脚本,该脚本将在终端窗口中运行。我尝试过同时使用 Shell 函数和 MacScript 函数,但 VBA 解释器似乎在这两种情况下都找不到脚本。

根据 VBA 参考文档,以下内容应该有效:

 RetVal = Shell("Macintosh HD:Applications:Calculator.app", vbNormalFocus)

这会产生运行时错误 53“找不到文件”。

有什么建议吗?

【问题讨论】:

  • 此位置是否存在计算器应用程序?
  • 最新款式可能是这样的RetValue = Shell("/System/Applications/Calculator.app", vbNormalFocus)?

标签: excel vba macos shell


【解决方案1】:

希望您现在已经找到答案,但您只需要完整路径:

RetVal = Shell("Macintosh HD:Applications:Calculator.app:" & _
              "Contents:MacOS:Calculator", vbNormalFocus)

另一个例子是这样的:

RetVal = Shell("Macintosh HD:Users:brownj:Documents:" & _
              "rnaseq:IGV_2.0.14:igv.sh", vbNormalFocus)

【讨论】:

  • 由于沙盒,这可能不再适用于 Excel 2016 for Mac
【解决方案2】:

Mac 上的Shell() VBA 函数似乎需要将完整路径作为 HFS 样式路径(使用冒号而不是斜杠)。它似乎也不像在 Windows 上那样接受参数(如果添加了任何参数,则会报告“找不到路径”错误)。

也可以使用MacScript() VBA 函数:MacScript("do shell script ""command""")。这可能是最简单的选择,也是我建议做的。缺点是它有相当多的开销(每次调用 100-200 毫秒)。

另一种选择是标准 C 库中的 system() 函数:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari --args http://www.google.com")
    Debug.Print Str(result)
End Sub

有关文档,请参阅 http://pubs.opengroup.org/onlinepubs/009604499/functions/system.html

system() 只返回退出代码。如果你想得到命令的输出,你可以使用popen()

Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long

Function execShell(command As String, Optional ByRef exitCode As Long) As String
    Dim file As Long
    file = popen(command, "r")

    If file = 0 Then
        Exit Function
    End If

    While feof(file) = 0
        Dim chunk As String
        Dim read As Long
        chunk = Space(50)
        read = fread(chunk, 1, Len(chunk) - 1, file)
        If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
        End If
    Wend

    exitCode = pclose(file)
End Function

Sub RunTest()
    Dim result As String
    Dim exitCode As Long
    result = execShell("echo Hello World", exitCode)
    Debug.Print "Result: """ & result & """"
    Debug.Print "Exit Code: " & str(exitCode)
End Sub

请注意,以上示例中的几个Long 参数是指针,因此如果发布了 64 位版本的 Mac Word,则必须进行更改。

【讨论】:

  • 谢谢!这非常有帮助:Another alternative is the system() function from the standard C library:
  • "请注意,上面示例中的几个 Long 参数是指针,因此如果发布了 64 位版本的 Mac Word,则必须进行更改。"那真的发生了!现在我该怎么办?
  • 完美~!对于更高版本的 Excel,请不要忘记在 'Function' 前面添加 'PtrSafe',例如“Private Declare Function system Lib...”。
  • 请参阅下面的回答,了解 Robert 代码的更新,使其与 64 位 Office 兼容并更改沙盒。
【解决方案3】:

另一个问题完全是这样的:由于 AppleScript 环境和您用户的 bash 环境之间的差异,权限导致您的脚本失败。这个问答帮助我弄清楚了这一点。为了让我的脚本正常工作,我必须解决一些路径和权限问题(不是脚本本身,而是脚本所涉及的问题)。

这是我的建议,希望能比我在使用 AppleScript 编辑器之前看到的无意义的 Excel 错误更深入地了解您的故障排除:

  1. 使用 AppleScript 编辑器确认脚本实际上可以作为任何用户使用,并且使用了任何环境变量:

    1. 在 Spotlight 中,开始输入“applescript editor”,直到它出现,然后单击它
    2. 创建一个新的 AppleScript 编辑器文件
    3. 在新文件中输入您的简单脚本不要加双引号 - 我的意思是

      do shell script "parseCsvAndOpen.sh"
      
    4. 点击脚本的“运行”按钮
    5. 跟踪任何问题,进行更改,然后重复点击“运行”按钮,直到您在 AppleScript 编辑器中执行它
      • 这里的好消息是,如果您需要返回 StackOverflow 或 Google 寻求帮助,您的搜索范围会缩小 ;-)
  2. 现在将您的简单脚本从 AppleScript 编辑器复制到您的 vba 并确认它仍然有效

    1. 我能够将我的双引号加倍并在 MacScript 代码之后将其放在双引号中:

      MacScript "do shell script ""parseCsvAndOpen.sh"""
      

      确实是一个,两个,然后是三个双引号字符! (大概是转义双引号)

【讨论】:

  • 我需要:MacScript "do shell script ""/Users/xxx/.../doit.sh""" 即脚本的完整 shell 路径
【解决方案4】:

只是没有足够的分数来发表评论,但觉得这是对 Robin Knights 答案的补充。当然,他的学分仍然属于他。
对于 Excel 15.18 (2015),标准 C 库中 system() 函数中使用的 open 调用不再需要 --args 关键字:

Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long

Sub RunSafari()
    Dim result As Long
    result = system("open -a Safari http://www.google.com")
    Debug.Print Str(result)
End Sub

这很好用。没有在 2011 年测试过。

【讨论】:

    【解决方案5】:

    对于使用 64 位 Office 的任何人,此处更新了 Robert 的代码以兼容 32 位和 64 位版本。请注意,由于沙盒的更改,必须在声明中使用 libc 的完整路径,否则在 OSX/Office 的非版本中,您最终会收到错误 53“找不到文件”。

    #If Mac Then
      #If VBA7 Then
        ' 64 bit Office:mac
        Private Declare PtrSafe Function popen Lib "/usr/lib/libc.dylib" (ByVal command As String, ByVal mode As String) As LongPtr
        Private Declare PtrSafe Function pclose Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As Long
        Private Declare PtrSafe Function fread Lib "/usr/lib/libc.dylib" (ByVal outStr As String, ByVal size As LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
        Private Declare PtrSafe Function feof Lib "/usr/lib/libc.dylib" (ByVal file As LongPtr) As LongPtr
        Private file As LongPtr
      #Else
        ' 32 bit Office:mac
        Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long
        Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
        Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long
        Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long
        Private file As Long
      #End If
    
      Public Function execShell(command As String, Optional ByRef exitCode As Long) As String
        file = popen(command, "r")
        
        If file = 0 Then
          Exit Function
        End If
        
        While feof(file) = 0
          Dim chunk As String
          Dim read As Long
          chunk = SPACE(50)
          read = fread(chunk, 1, Len(chunk) - 1, file)
          If read > 0 Then
            chunk = Left$(chunk, read)
            execShell = execShell & chunk
          End If
        Wend
        
        exitCode = pclose(file) ' 0 = success
      End Function
    
    #End If
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 2018-03-05
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多