在 Swift 脚本中使用管道链接 shell 命令

Chaining shell commands with pipe in a Swift script

我正在尝试在 Swift 脚本中将 shell 命令链接在一起。有问题的实际命令是 gource 的输出通过管道传输到 ffmpeg 的输入,但这里有一个简化的、人为的示例,说明我正在尝试执行的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let echo = Process()

echo.launchPath ="/usr/bin/env"
echo.arguments = ["echo","foo\
bar\
baz\
baz","|","uniq"]

let pipe = Pipe()
echo.standardOutput = pipe

echo.launch()
echo.waitUntilExit()

// Get the data
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)

print(output ??"no output")

预期输出:

1
2
3
foo
bar
baz

实际输出:

1
2
3
4
foo
bar
baz
baz | uniq

| 被解释为最后一个参数的一部分。如何在 Swift 脚本中将命令链接在一起,以便数据从一个流到下一个?我尝试了在两个 Process 之间分配 standardInstandardOut 并使用 Pipe() 的各种组合,但要么我做错了,要么我没有将正确的部分连接在一起。


我在 zadr 的帮助下得到了答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import Foundation

let pipe = Pipe()

let echo = Process()
echo.launchPath ="/usr/bin/env"
echo.arguments = ["echo","foo\
bar\
baz\
baz"]
echo.standardOutput = pipe

let uniq = Process()
uniq.launchPath ="/usr/bin/env"
uniq.arguments = ["uniq"]
uniq.standardInput = pipe

let out = Pipe()
uniq.standardOutput = out

echo.launch()
uniq.launch()
uniq.waitUntilExit()

let data = out.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)

print(output ??"no output")


对于可能遇到相同问题的其他人,这是我从 Zev 的回答中得出的适合创建 SHA1 HMAC 哈希的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func getHMAC(forValue value: String, key: String) -> String {

    let pipe = Pipe()

    let echo = Process()
    echo.launchPath ="/usr/bin/env"
    echo.arguments = ["echo","-n", value]
    echo.standardOutput = pipe

    let task = Process()
    task.launchPath ="/usr/bin/env"
    task.arguments = ["openssl","sha1","-hmac", key]
    task.standardInput = pipe

    let output = Pipe()
    task.standardOutput = output

    echo.launch()
    task.launch()
    task.waitUntilExit()

    let data = output.fileHandleForReading.readDataToEndOfFile()
    return NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
}

这在从需要 HTTP 标头中的哈希值的 Swift 脚本中进行简单的 API 调用时特别有用。据我所知,这是唯一可行的方法(因为我们无法在 Swift 脚本中使用 Objective-C CommonCrypto 框架)


你应该看看这个。这是通过链接进行管道传输的简单方法的示例。 https://gist.github.com/eahrold/b5c5fd455225a8726e1cc31708e139db

所以你可以像

1
2
3
4
5
6
7
8
9
 let ls = Process("/bin/ls", ["-al"])
 let grep = Process("/usr/bin/grep", ["com"])
 let cut = Process("/usr/bin/awk", ["{print $3}"])

 ls.pipe(grep).pipe(cut).complete {
    message, status in
    print("Your results: \\(message)")
 }
 ls.launch()