Looking at what Python (subprocess) and Go (os.exec) do, it looks like they agree on the following: - executable and arguments are merged in one array - they don't require full path for the executable - they don't expand tildes - blocking calls are the default - they are more explicit about stdin, stdout, stderr
Some example scenarios based on that, with possible swift code: 1) Run a command and ignore output Python: subprocess.run(["sleep", "1"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) Go: cmd := exec.Command("sleep", "1") err := cmd.Run() Possible Swift: try Process.run(["sleep", "1"]) 2) Run a command and capture stdout Python: out = subprocess.check_output(["ls", "-l"]) Go: cmd := exec.Command("ls", "-l") out, err := cmd.Output() Possible Swift: let proc = try Process.run(["ls", "-l"]) let out = proc.stdout.read() // proc.stdout is OutputStream, assumes read() exists and returns Data // stderr available at proc.stderr 3) Run a command and capture both stdout and stder together Python: out = subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT) Go: cmd := exec.Command("ls", "-l") out, err := cmd.CombinedOutput() Possible Swift: let proc = try Process.run(["ls", "-l"], combinedOutput: true) let out = proc.stdout.read() 4) Shell out Python: subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT, shell=True) Go: cmd := exec.Command("sh", "-c", "ls -l") out, err := cmd.CombinedOutput() Possible Swift: let proc = try Process.run(["sh", "-c", "ls -l"], combinedOutput: true) let out = proc.stdout.read() 5) Pipe to stdin Python: p = subprocess.Popen(["wc"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.stdin.write(b'blah') p.stdin.close() out = p.stdout.read() Go: cmd := exec.Command("wc") stdin, err := cmd.StdinPipe() io.WriteString(stdin, "blah") out = cmd.CombinedOutput() Possible Swift: let stdin = InputStream(data: "blah".data(using: .utf8)) let proc = try Process.run(["wc"], stdin: stdin, combinedOutput: true) let out = proc.stdout.read() 6) Async Python: p = subprocess.Popen(["sleep", "5"]) p.wait() Go: cmd := exec.Command("sleep", "5") err := cmd.Start() err2 := cmd.Wait() Possible Swift: let proc = Process(["sleep", "5"]) try proc.start() try proc.wait() On Fri, Nov 17, 2017 at 9:34 PM, Tony Parker via swift-corelibs-dev < swift-corelibs-dev@swift.org> wrote: > Hi Abhi, > > It does seem like there is a possibility of some better convenience API > here. > > Any ideas on what form it would take? A class method on Process that > returns the output, maybe? > > - Tony > > On Nov 16, 2017, at 3:34 PM, Abhi Beckert via swift-corelibs-dev < > swift-corelibs-dev@swift.org> wrote: > > Swift is a great shell scripting language except for it's lack of any API > to execute UNIX commands. Compare these two shell scripts: > > #!/usr/bin/php > <? > > $files = `find ~/Desktop -name *.png`; > > foreach (explode("\n", $files) as $file) { > // do something with $file > } > > > - > > #!/usr/bin/swift > > import Foundation > > let process = Process() > process.launchPath = "/usr/bin/find" > process.arguments = [ > NSString(string:"~/Desktop").expandingTildeInPath, > "-name", > "*.png" > ] > > let output = Pipe() > process.standardOutput = output > > process.launch() > > let files: String > if let filesUtf8 = NSString(data: > output.fileHandleForReading.readDataToEndOfFile(), > encoding: String.Encoding.utf8.rawValue) { > files = filesUtf8 as String > } else { > files = NSString(data: output.fileHandleForReading.readDataToEndOfFile(), > encoding: String.Encoding.isoLatin1.rawValue) as NSString! as String > } > > files.enumerateLines { file, _ in > // do something with file > } > > > It's a contrived example, I could have used NSFileManager, but I run into > this all the time integrating with more complex tools such as rsync. > > Adding my own high level wrapper around the Process command isn't an > option since there is no good way to import code from another file when > executing swift asa shell script. All your code needs to be in one file. > > - Abhi > _______________________________________________ > swift-corelibs-dev mailing list > swift-corelibs-dev@swift.org > https://lists.swift.org/mailman/listinfo/swift-corelibs-dev > > > > _______________________________________________ > swift-corelibs-dev mailing list > swift-corelibs-dev@swift.org > https://lists.swift.org/mailman/listinfo/swift-corelibs-dev > >
_______________________________________________ swift-corelibs-dev mailing list swift-corelibs-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-corelibs-dev