[swift-corelibs-dev] Better integration with UNIX tools
Nick Keets
nick.keets at gmail.com
Mon Nov 20 06:37:43 CST 2017
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 at 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 at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
>
>
>
> _______________________________________________
> swift-corelibs-dev mailing list
> swift-corelibs-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-corelibs-dev/attachments/20171120/456cbdbc/attachment.html>
More information about the swift-corelibs-dev
mailing list