Commands
SSHKit has two ways to run a remote command.
Collected (batch)
Use execute when the command will produce a bounded amount of output and you want it all together.
let result = try await connection.execute("uname -a")
let stdout = String(data: result.standardOutput, encoding: .utf8) ?? ""
print(stdout)
print("exit:", result.exitStatus)
SSHCommandResult has standardOutput, standardError, exitStatus, and an optional exitSignal. Non-zero exit is not thrown — inspect exitStatus after the call.
Streamed
Use openCommand when you need to consume output as it arrives or write to the command’s stdin.
let command = try await connection.openCommand("tail -F /var/log/app.log")
for await event in command.events {
switch event {
case .standardOutput(let data):
if let text = String(data: data, encoding: .utf8) {
print(text, terminator: "")
}
case .standardError:
break // PTY-backed channels can emit this
case .closed(let status, let signal):
print("closed status=\(status) signal=\(signal ?? "-")")
return
}
}
command.events is an AsyncStream<SSHCommandEvent> that finishes when the channel closes. You can write to stdin while the stream is live (command.write(...)) and call command.sendEOF() or command.close() when done.
Exit status & signals
The .closed event carries both an Int32 exit status and an optional exitSignal string. The two are mutually exclusive at the wire level:
- If the server reports a normal exit,
exitSignalisnilandexitStatusreflects the process return value. - If the server reports a signal termination (e.g.
TERM,KILL),exitSignalis set andexitStatusis usually zero.