How to run a Process in Swift 3.0 with standard in

2019-02-26 21:27发布

I have a problem when run MySQL restore dump file with Swift Process.

  let command = "/usr/local/bin/mysql -h theHost -P 3306 -u root -pTheInlinePassword example_database < dumpFile.sql"
  let task = Process()
  task.launchPath = "/usr/bin/env"
  task.arguments = command.components(separatedBy: " ")
  task.launch()

The problem is Process doesn't understand standard input <. How I can run command with standard input like this. Thanks.

Update:

  let task = Process()
  task.launchPath = "/usr/local/bin/mysql"
  task.arguments =  ["-h", "theHost", "-P", "3306", "-u", "root", "-pTheInLinePassword", "example_data"]
  task.standardInput = try! FileHandle(forReadingFrom: filePath!)
  task.launch()

I tried code bellow. This works for me

2条回答
老娘就宠你
2楼-- · 2019-02-26 22:18

The < filename syntax is a feature provided by the shell, not something that programs themselves ever deal with.

The proper way to handle this is to construct a FileHandle for reading from dumpFile.sql and then set that FileHandle as the standardInput property of the Process.

As a side note, I don't know why you're using /usr/bin/env as your launch path, since you're not relying on PATH lookup or setting any environment variables.

let input = try FileHandle(forReadingFrom: URL(fileURLWithPath: "dumpFile.sql"))
let task = Process()
task.launchPath = "/usr/bin/mysql"
task.arguments = ["-h", "theHost", "-P", "3306", "-u", "root", "-pTheInlinePassword", "example_database"]
task.standardInput = input
task.launch()
查看更多
做自己的国王
3楼-- · 2019-02-26 22:27

I had been trying to get this to work for some time using Process and have been unsuccessful. What did work, however, is diving into some of the Darwin framework and using posix_spawn.

This script will spawn a subprocess and hand control over to it until the process terminates (much like the os.system call in Python).

import Darwin

func run(_ cmd: String) -> Int32 {
    var pid: Int32 = 0
    let args = ["/bin/sh", "-c", cmd]
    let argv: [UnsafeMutablePointer<CChar>?] = args.map{ $0.withCString(strdup) }
    defer { for case let arg? in argv { free(arg) } }
    if posix_spawn(&pid, argv[0], nil, nil, argv + [nil], environ) < 0 {
        print("ERROR: Unable to spawn")
        return 1
    }
    var status: Int32 = 0
    _ = waitpid(pid, &status, 0)
    return status
}

I am sure this script could be improved, but might get you closer to where you want to go.

Hope this helps!

查看更多
登录 后发表回答