     public func execute() throws -> String {
         self.startExecution()
 
+        commandsToKill.append(self)
+
         self.process.waitUntilExit()
+        self.removeFromCommandsToKill()
 
         guard self.process.terminationStatus == 0 else {
             throw LocalUserReportableError(source: "ShellCommand", operation: "executing command", message: "Stopping execution", reason: .user)


    public func terminate() {
        self.process.terminate()
    }

    public func waitUntilExit() {
        self.process.waitUntilExit()
    }

    public func pipe(to: String) -> ShellCommand {
        return ShellCommand(to, parentCommand: self)
    }

    public var description: String {
        return self.command.joined(separator: " ")
    }
}

private extension ShellCommand {
    func startExecution() {


public final class ShellCommand: CustomStringConvertible {
    private let command: [String]

    static let once: Void = {
        signal(SIGINT, { _ in
            for command in commandsToKill {
                command.terminate()
            }
        })
    }()

    #if os(Linux)
        fileprivate let process = Task()
