【问题标题】:How to execute terminal command in swift?如何快速执行终端命令?
【发布时间】:2017-08-18 06:47:48
【问题描述】:

我是 Sswift 的新手。如何从 Swift 代码运行这个过程?

  1. 打开终端窗口
  2. 执行cd Desktop/firebase-mac
  3. 执行npm start

我实际上想要做的是从 Swift 代码点击启动 Node 服务器。

【问题讨论】:

  • 我已经尝试过 task.launchPath = "/usr/bin/env" task.arguments = ["/Users/aharon/Desktop"] 并且我得到了 Permission denied
  • 想要在终端中运行命令有多种原因,但从程序中打开终端来执行此操作几乎总是错误的。如果他们愿意,让用户在终端中运行程序。如果您不熟悉外壳,请相信我的话;你通常不需要终端来运行程序,当你这样做时,这应该是调用用户的选择。

标签: node.js swift bash macos terminal


【解决方案1】:

使用swift-commands

import Commands

Commands.Bash.system("cd /Users/${name}/Desktop/firebase-mac && npm start")

【讨论】:

    【解决方案2】:

    完整示例:

    • 转到某个目录,比如说Desktop
    • 创建一个名为 swsh 的文件,并添加到其中(纯文本,而不是 rtf 或 doc)
    #!/usr/bin/env xcrun swift
    
    import Foundation
    
    func shell(launchPath: String, arguments: [String]) -> String {
    
        let process = Process()
        process.launchPath = launchPath
        process.arguments = arguments
    
        let pipe = Pipe()
        process.standardOutput = pipe
        process.launch()
    
        let output_from_command = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: String.Encoding.utf8)!
    
        // remove the trailing new-line char
        if output_from_command.characters.count > 0 {
            let lastIndex = output_from_command.index(before: output_from_command.endIndex)
            return output_from_command[output_from_command.startIndex ..< lastIndex]
        }
        return output_from_command
    }
    
    let output = shell(launchPath: "/bin/date", arguments: [ ])
    print(output)
    

    保存,然后:

    • 打开终端
    • 输入cd ~/Desktop
    • 使用chmod 755 swsh
    • 并运行swift script 为:./swsh

    你会得到如下输出:

    Sat Mar 25 14:31:39 CET 2017
    

    编辑您的swsh 并将shell(... 行更改为:

    let output = shell(launchPath: "/usr/bin/env", arguments: [ "date" ])
    

    再次运行它会得到日期,但是现在:

    • swsh 执行了/usr/bin/env,(带有参数date
    • /usr/bin/env 找到命令date
    • 并执行它

    现在,在~/Desktop 中创建另一个文件并将其命名为from_swift

    添加进去

    echo "Today's date is $(date)"
    

    更改文件swshshell 行更改为:

    let output = shell(launchPath: "./from_swift", arguments: [ ])
    

    注意,./from_swift - 使用. 的相对路径(我们在~/Desktop 目录中)。运行 swift 程序:

    ./swsh
    

    输出:

    2017-03-25 14:42:20.176 swift[48479:638098] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'launch path not accessible'
    

    当然,脚本from_swift 还不是可执行文件。所以执行:

    chmod 755 from_swift
    # and run
    ./swsh
    

    又报错了:

    2017-03-25 14:45:38.523 swift[48520:639486] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Couldn't posix_spawn: error 8'
    

    这是因为from_swift 是一个脚本(不是编译后的二进制文件),所以操作系统需要知道哪个二进制文件应该解释脚本内容。因为这是 shell script,所以将 from_swift 脚本编辑为:

    #!/bin/sh
    echo "Today's date is $(date)"
    

    注意添加的“shebang”行:#!/bin/sh。运行 swift ./swsh 会得到

    Today's date is Sat Mar 25 14:50:23 CET 2017
    

    Horay,你从swift 执行了你的第一个bash 脚本。 ;)

    当然你可以在shebang中使用/usr/bin/env,所以现在把from_swift的内容改成:

    #!/usr/bin/env perl
    
    use strict;
    use utf8;
    use English;
    binmode STDOUT, ":utf8";
    
    printf "The $EXECUTABLE_NAME (ver:$PERL_VERSION) runs me: $0\n";
    printf "I ❤️ perl!\n";
    

    运行./swsh 会得到:

    The /usr/bin/perl (ver:v5.18.2) runs me: ./from_swift
    I ❤️ perl!
    

    注意,我们在 ./swsh 文件中更改了 nothing,只更改了脚本文件 ./from_swift

    以上所有使用:

    $ uname -a
    Darwin nox.local 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64
    $ swift --version
    Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
    Target: x86_64-apple-macosx10.9
    

    因此,很容易创建和执行任何脚本。所以,你可以输入你的~/Desktop/from_swift

    #!/bin/sh
    cd $HOME/Desktop/firebase-mac
    npm start
    

    可以直接swsh 执行(Jens Meder 建议),但使用此方法,您可以轻松地执行给定脚本文件中的任何内容。

    请记住:process.launch() 执行任一:

    • 编译的二进制文件
    • 或脚本文件,但脚本文件
      • 必须shebang这一行
      • 并且必须可以使用chmod 755 /path/to/script.file 执行

    【讨论】:

      【解决方案3】:

      要启动传递一个参数的进程,您只需要一行:

      Process.launchedProcess(launchPath: "/Users/aharon/Desktop/firebase-mac/npm", arguments: ["start"])
      

      但是考虑到如果应用程序是沙盒的,则文字路径不起作用。

      【讨论】:

      • 我创建了一个 shell 脚本 #!/bin/bash cd /users/aharon/desktop/firebase-mac npm start 当我运行它时它工作正常,但是如果我从我得到 line 3: npm: command not found 的代码运行它
      • 你试过我的代码了吗?忘记额外的cd 命令。你不需要它。只需传递完整路径/users/aharon/desktop/firebase-mac/npm start
      • 我得到“启动路径不可访问”
      【解决方案4】:

      您可以只使用以下代码 sn-p,例如,run("npm start")。它将在默认 shell /bin/sh 上执行命令,并将输出作为 String 返回。

      func run(_ cmd: String) -> String? {
          let pipe = Pipe()
          let process = Process()
          process.launchPath = "/bin/sh"
          process.arguments = ["-c", String(format:"%@", cmd)]
          process.standardOutput = pipe
          let fileHandle = pipe.fileHandleForReading
          process.launch()
          return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
      }
      

      如果您想使用不同的 bash,则只需替换 launchPath,例如,对于 Zsh,它将是 /bin/zsh

      【讨论】:

      • 对于 "/bin/sh" 我得到 "command not found" 对于 "/bin/env" 我得到 "启动路径不可访问"
      • 你能试试/bin/bash吗?
      • 您能在新的终端窗口中运行echo $SHELL 并尝试该输出吗?对我来说,它输出 /bin/zsh 因为我使用 Zsh 作为 shell。
      • 结果是/bin/bash
      • 我创建了一个 shell 脚本 #!/bin/bash cd /users/aharon/desktop/firebase-mac npm start 当我运行它时它工作正常,但是如果我从我得到 line 3: npm: command not found 的代码运行它
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-05
      • 2015-05-27
      • 2015-06-13
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多