<div dir="ltr"><div>Looking at what Python (subprocess) and Go (os.exec) do, it looks like they agree on the following:</div><div> - executable and arguments are merged in one array</div><div> - they don&#39;t require full path for the executable</div><div> - they don&#39;t expand tildes</div><div> - blocking calls are the default</div><div> - they are more explicit about stdin, stdout, stderr</div><div><br></div><div>Some example scenarios based on that, with possible swift code:</div><div><br></div><div>1) Run a command and ignore output</div><div><br></div><div>Python:</div><div>    subprocess.run([&quot;sleep&quot;, &quot;1&quot;], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)</div><div><br></div><div>Go:</div><div>    cmd := exec.Command(&quot;sleep&quot;, &quot;1&quot;)</div><div>    err := cmd.Run()</div><div><br></div><div>Possible Swift:</div><div>    try Process.run([&quot;sleep&quot;, &quot;1&quot;])</div><div><br></div><div><br></div><div>2) Run a command and capture stdout</div><div><br></div><div>Python:</div><div>    out = subprocess.check_output([&quot;ls&quot;, &quot;-l&quot;])</div><div><br></div><div>Go:</div><div><br></div><div>    cmd := exec.Command(&quot;ls&quot;, &quot;-l&quot;)</div><div>    out, err := cmd.Output()</div><div><br></div><div>Possible Swift:</div><div><br></div><div>    let proc = try Process.run([&quot;ls&quot;, &quot;-l&quot;])</div><div>    let out = proc.stdout.read() // proc.stdout is OutputStream, assumes read() exists and returns Data</div><div>    // stderr available at proc.stderr</div><div><br></div><div><br></div><div>3) Run a command and capture both stdout and stder together</div><div><br></div><div>Python:</div><div>    out = subprocess.check_output([&quot;ls&quot;, &quot;-l&quot;], stderr=subprocess.STDOUT)</div><div><br></div><div>Go:</div><div>    cmd := exec.Command(&quot;ls&quot;, &quot;-l&quot;)</div><div>    out, err := cmd.CombinedOutput()</div><div><br></div><div>Possible Swift:</div><div>    let proc = try Process.run([&quot;ls&quot;, &quot;-l&quot;], combinedOutput: true)</div><div>    let out = proc.stdout.read()</div><div><br></div><div><br></div><div>4) Shell out</div><div><br></div><div>Python:</div><div>    subprocess.check_output([&quot;ls&quot;, &quot;-l&quot;], stderr=subprocess.STDOUT, shell=True)</div><div><br></div><div>Go:</div><div>    cmd := exec.Command(&quot;sh&quot;, &quot;-c&quot;, &quot;ls -l&quot;)</div><div>    out, err := cmd.CombinedOutput()</div><div><br></div><div>Possible Swift:</div><div>    let proc = try Process.run([&quot;sh&quot;, &quot;-c&quot;, &quot;ls -l&quot;], combinedOutput: true)</div><div>    let out = proc.stdout.read()</div><div><br></div><div><br></div><div>5) Pipe to stdin</div><div><br></div><div>Python:</div><div>    p = subprocess.Popen([&quot;wc&quot;], stdin=subprocess.PIPE, stdout=subprocess.PIPE)</div><div>    p.stdin.write(b&#39;blah&#39;)</div><div>    p.stdin.close()</div><div>    out = p.stdout.read()</div><div><br></div><div>Go:</div><div>    cmd := exec.Command(&quot;wc&quot;)</div><div>    stdin, err := cmd.StdinPipe()</div><div>    io.WriteString(stdin, &quot;blah&quot;)</div><div>    out = cmd.CombinedOutput()</div><div><br></div><div>Possible Swift:</div><div>    let stdin = InputStream(data: &quot;blah&quot;.data(using: .utf8))</div><div>    let proc = try Process.run([&quot;wc&quot;], stdin: stdin, combinedOutput: true)</div><div>    let out = proc.stdout.read()</div><div><br></div><div>6) Async</div><div><br></div><div>Python:</div><div>    p = subprocess.Popen([&quot;sleep&quot;, &quot;5&quot;])</div><div>    p.wait()</div><div><br></div><div>Go:</div><div>    cmd := exec.Command(&quot;sleep&quot;, &quot;5&quot;)</div><div>    err := cmd.Start()</div><div>    err2 := cmd.Wait()</div><div><br></div><div>Possible Swift:</div><div>    let proc = Process([&quot;sleep&quot;, &quot;5&quot;])</div><div>    try proc.start()</div><div>    try proc.wait()</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Nov 17, 2017 at 9:34 PM, Tony Parker via swift-corelibs-dev <span dir="ltr">&lt;<a href="mailto:swift-corelibs-dev@swift.org" target="_blank">swift-corelibs-dev@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Hi Abhi,<div><br></div><div>It does seem like there is a possibility of some better convenience API here.</div><div><br></div><div>Any ideas on what form it would take? A class method on Process that returns the output, maybe?</div><div><br></div><div>- Tony<br><div><br><blockquote type="cite"><div><div class="h5"><div>On Nov 16, 2017, at 3:34 PM, Abhi Beckert via swift-corelibs-dev &lt;<a href="mailto:swift-corelibs-dev@swift.org" target="_blank">swift-corelibs-dev@swift.org</a>&gt; wrote:</div><br class="m_-3069825369200109882Apple-interchange-newline"></div></div><div><div><div class="h5"><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">Swift is a great shell scripting language except for it&#39;s lack of any API to execute UNIX commands. Compare these two shell scripts:<br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><blockquote type="cite" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div>#!/usr/bin/php<br></div><div>&lt;?<br></div><div><br></div><div>$files = `find ~/Desktop -name *.png`;<br></div><div><br></div><div>foreach (explode(&quot;\n&quot;, $files) as $file) {<br></div><div>  // do something with $file<br></div><div>}<br></div></blockquote><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">-<br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><blockquote type="cite" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div>#!/usr/bin/swift<br></div><div><br></div><div>import Foundation<br></div><div><br></div><div>let process = Process()<br></div><div>process.launchPath = &quot;/usr/bin/find&quot;<br></div><div>process.arguments = [<br></div><div>  NSString(string:&quot;~/Desktop&quot;).<wbr>expandingTildeInPath,<br></div><div>  &quot;-name&quot;,<br></div><div>  &quot;*.png&quot;<br></div><div>]<br></div><div><br></div><div>let output = Pipe()<br></div><div>process.standardOutput = output<br></div><div><br></div><div>process.launch()<br></div><div><br></div><div>let files: String<br></div><div>if let filesUtf8 = NSString(data: output.fileHandleForReading.<wbr>readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {<br></div><div>  files = filesUtf8 as String<br></div><div>} else {<br></div><div>  files = NSString(data: output.fileHandleForReading.<wbr>readDataToEndOfFile(), encoding: String.Encoding.isoLatin1.<wbr>rawValue) as NSString! as String<br></div><div>}<br></div><div><br></div><div>files.enumerateLines { file, _ in<br></div><div>  // do something with file<br></div><div>}<br></div></blockquote><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">It&#39;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.<br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">Adding my own high level wrapper around the Process command isn&#39;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.<br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">- Abhi</div></div></div><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">______________________________<wbr>_________________</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important">swift-corelibs-dev mailing list</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="mailto:swift-corelibs-dev@swift.org" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">swift-corelibs-dev@swift.org</a><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="https://lists.swift.org/mailman/listinfo/swift-corelibs-dev" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>corelibs-dev</a></div></blockquote></div><br></div></div><br>______________________________<wbr>_________________<br>
swift-corelibs-dev mailing list<br>
<a href="mailto:swift-corelibs-dev@swift.org">swift-corelibs-dev@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-corelibs-dev" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>corelibs-dev</a><br>
<br></blockquote></div><br></div>