On Nov 20, 2017, at 4:37 AM, Nick Keets <nick.keets@gmail.com> wrote:
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 <mailto: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 <mailto: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 <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org <mailto:swift-corelibs-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev