Files
SwiftShell/index.html
T
2018-03-04 17:25:54 +01:00

614 lines
48 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<title>SwiftShell Reference</title>
<link rel="stylesheet" type="text/css" href="css/jazzy.css" />
<link rel="stylesheet" type="text/css" href="css/highlight.css" />
<meta charset='utf-8'>
<script src="js/jquery.min.js" defer></script>
<script src="js/jazzy.js" defer></script>
</head>
<body>
<a title="SwiftShell Reference"></a>
<header>
<div class="content-wrapper">
<p><a href="index.html">SwiftShell Docs</a> (70% documented)</p>
<p class="header-right"><a href="https://github.com/kareman/SwiftShell"><img src="img/gh.png"/>View on GitHub</a></p>
</div>
</header>
<div class="content-wrapper">
<p id="breadcrumbs">
<a href="index.html">SwiftShell Reference</a>
<img id="carat" src="img/carat.png" />
SwiftShell Reference
</p>
</div>
<div class="content-wrapper">
<nav class="sidebar">
<ul class="nav-groups">
<li class="nav-group-name">
<a href="Classes.html">Classes</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Classes/AsyncCommand.html">AsyncCommand</a>
</li>
<li class="nav-group-task">
<a href="Classes/FileHandleStream.html">FileHandleStream</a>
</li>
<li class="nav-group-task">
<a href="Classes/MainContext.html">MainContext</a>
</li>
<li class="nav-group-task">
<a href="Classes/RunOutput.html">RunOutput</a>
</li>
<li class="nav-group-task">
<a href="Classes/StdoutStream.html">StdoutStream</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Global Variables.html">Global Variables</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Global Variables.html#/s:10SwiftShell5FilesSo11FileManagerCv">Files</a>
</li>
<li class="nav-group-task">
<a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Enums.html">Enumerations</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Enums/CommandError.html">CommandError</a>
</li>
<li class="nav-group-task">
<a href="Enums/FileError.html">FileError</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Extensions.html">Extensions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Extensions/FileHandle.html">FileHandle</a>
</li>
<li class="nav-group-task">
<a href="Extensions/FileHandle.html">FileHandle</a>
</li>
<li class="nav-group-task">
<a href="Extensions/LazyCollectionProtocol.html">LazyCollectionProtocol</a>
</li>
<li class="nav-group-task">
<a href="Extensions/Process.html">Process</a>
</li>
<li class="nav-group-task">
<a href="Extensions/String.html">String</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Functions.html">Functions</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell1poi10Foundation3URLVAE_SStF">+(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell2eeoiSbAA12CommandErrorO_ADtF">==(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4exits5NeverOs5Error_p_SS4fileSi4linetF">exit(_:file:line:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4exits5NeverOx12errormessage_Si9errorcodeSS4fileSi4linetlF">exit(errormessage:errorcode:file:line:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4openAA14ReadableStream_p10Foundation3URLV_SSADE8EncodingV8encodingtKF">open(_:encoding:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4openAA14ReadableStream_pSS_SS10FoundationE8EncodingV8encodingtKF">open(_:encoding:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4openAA14WritableStream_p10Foundation3URLV10forWriting_Sb9overwriteSSADE8EncodingV8encodingtKF">open(forWriting:overwrite:encoding:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell4openAA14WritableStream_pSS10forWriting_Sb9overwriteSS10FoundationE8EncodingV8encodingtKF">open(forWriting:overwrite:encoding:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell3runAA9RunOutputCSS_SayypGdSb07combineE0tF">run(_:_:combineOutput:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell3runAA9RunOutputCSS4bash_Sb07combineE0tF">run(bash:combineOutput:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell11runAndPrintySS_SayypGdtKF">runAndPrint(_:_:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell11runAndPrintySS4bash_tKF">runAndPrint(bash:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell8runAsyncAA0D7CommandCSS_SayypGdSS4fileSi4linetF">runAsync(_:_:file:line:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell8runAsyncAA0D7CommandCSS4bash_SS4fileSi4linetF">runAsync(bash:file:line:)</a>
</li>
<li class="nav-group-task">
<a href="Functions.html#/s:10SwiftShell7streamsAA14WritableStream_p_AA08ReadableE0_ptyF">streams()</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Protocols.html">Protocols</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Protocols.html#/CommandRunning">CommandRunning</a>
</li>
<li class="nav-group-task">
<a href="Protocols/CommandRunning.html">CommandRunning</a>
</li>
<li class="nav-group-task">
<a href="Protocols/Context.html">Context</a>
</li>
<li class="nav-group-task">
<a href="Protocols/ReadableStream.html">ReadableStream</a>
</li>
<li class="nav-group-task">
<a href="Protocols/WritableStream.html">WritableStream</a>
</li>
</ul>
</li>
<li class="nav-group-name">
<a href="Structs.html">Structures</a>
<ul class="nav-group-tasks">
<li class="nav-group-task">
<a href="Structs/CustomContext.html">CustomContext</a>
</li>
<li class="nav-group-task">
<a href="Structs/LazySplitSequence.html">LazySplitSequence</a>
</li>
<li class="nav-group-task">
<a href="Structs/PartialSourceLazySplitSequence.html">PartialSourceLazySplitSequence</a>
</li>
</ul>
</li>
</ul>
</nav>
<article class="main-content">
<section>
<section class="section">
<p>Run shell commands | <a href="https://github.com/kareman/Moderator">Parse command line arguments</a> | <a href="https://github.com/kareman/FileSmith">Handle files and directories</a></p>
<hr>
<p>Swift 4 | <a href="https://github.com/kareman/SwiftShell/tree/Swift3">Swift 3</a> | <a href="https://github.com/kareman/SwiftShell/tree/Swift2">Swift 2</a></p>
<p align="center">
<img src="https://raw.githubusercontent.com/kareman/SwiftShell/master/Misc/logo.png" alt="SwiftShell logo" />
</p>
<p><a href="https://travis-ci.org/kareman/SwiftShell"><img src="https://travis-ci.org/kareman/SwiftShell.svg?branch=master" alt="Build Status"></a> <img src="https://img.shields.io/badge/platforms-macOS%20%7C%20Linux-lightgrey.svg" alt="Platforms"> <a href="https://swift.org/package-manager"><img src="https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat" alt="Swift Package Manager" /></a> <a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible"></a> <a href="https://twitter.com/nottoobadsw"><img src="https://img.shields.io/badge/contact-@nottoobadsw-blue.svg?style=flat" alt="Twitter: @nottoobadsw" /></a></p>
<h1 id='swiftshell' class='heading'>SwiftShell</h1>
<p>A library for creating command-line applications and running shell commands in Swift. </p>
<h4 id='features' class='heading'>Features</h4>
<ul>
<li>[x] run commands, and handle the output.</li>
<li>[x] run commands asynchronously, and be notified when output is available.</li>
<li>[x] access the context your application is running in, like environment variables, standard input, standard output, standard error, the current directory and the command line arguments.</li>
<li>[x] create new such contexts you can run commands in.</li>
<li>[x] handle errors.</li>
<li>[x] read and write files.</li>
</ul>
<h4 id='see-also' class='heading'>See also</h4>
<ul>
<li><a href="http://kareman.github.io/SwiftShell">API Documentation</a>.</li>
<li>A <a href="https://www.skilled.io/kare/swiftshell">description</a> of the project on <a href="https://www.skilled.io">skilled.io</a>.</li>
</ul>
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
<h4 id='table-of-contents' class='heading'>Table of Contents</h4>
<ul>
<li><a href="#example">Example</a>
<ul>
<li><a href="#print-line-numbers">Print line numbers</a></li>
<li><a href="#others">Others</a></li>
</ul></li>
<li><a href="#context">Context</a>
<ul>
<li><a href="#main-context">Main context</a></li>
<li><a href="#example-1">Example</a></li>
</ul></li>
<li><a href="#streams">Streams</a>
<ul>
<li><a href="#writablestream">WritableStream</a></li>
<li><a href="#readablestream">ReadableStream</a></li>
<li><a href="#data">Data</a></li>
</ul></li>
<li><a href="#commands">Commands</a>
<ul>
<li><a href="#run">Run</a></li>
<li><a href="#print-output">Print output</a></li>
<li><a href="#asynchronous">Asynchronous</a></li>
<li><a href="#parameters">Parameters</a></li>
<li><a href="#errors">Errors</a></li>
</ul></li>
<li><a href="#setup">Setup</a>
<ul>
<li><a href="#stand-alone-project">Stand-alone project</a></li>
<li><a href="#script-file-using-marathon">Script file using Marathon</a></li>
<li><a href="#swift-package-manager">Swift Package Manager</a></li>
<li><a href="#carthage">Carthage</a></li>
<li><a href="#cocoapods">CocoaPods</a></li>
</ul></li>
<li><a href="#license">License</a></li>
</ul>
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<h2 id='example' class='heading'>Example</h2>
<h4 id='print-line-numbers' class='heading'>Print line numbers</h4>
<pre class="highlight swift"><code><span class="cp">#!/usr/bin/env swiftshell</span>
<span class="kd">import</span> <span class="kt">SwiftShell</span>
<span class="nf">do</span> <span class="p">{</span>
<span class="c1">// If there is an argument, try opening it as a file. Otherwise use standard input.</span>
<span class="k">let</span> <span class="nv">input</span> <span class="o">=</span> <span class="k">try</span> <span class="n">main</span><span class="o">.</span><span class="n">arguments</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="nf">map</span> <span class="p">{</span><span class="k">try</span> <span class="nf">open</span><span class="p">(</span><span class="nv">$0</span><span class="p">)}</span> <span class="p">??</span> <span class="n">main</span><span class="o">.</span><span class="n">stdin</span>
<span class="n">input</span><span class="o">.</span><span class="nf">lines</span><span class="p">()</span><span class="o">.</span><span class="nf">enumerated</span><span class="p">()</span><span class="o">.</span><span class="nf">forEach</span> <span class="p">{</span> <span class="p">(</span><span class="n">linenr</span><span class="p">,</span><span class="n">line</span><span class="p">)</span> <span class="k">in</span>
<span class="nf">print</span><span class="p">(</span><span class="n">linenr</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="s">":"</span><span class="p">,</span> <span class="n">line</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// Add a newline at the end.</span>
<span class="nf">print</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
<span class="p">}</span> <span class="nf">catch</span> <span class="p">{</span>
<span class="nf">exit</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>Launched with e.g. <code>cat long.txt | print_linenumbers.swift</code> or <code>print_linenumbers.swift long.txt</code> this will print the line number at the beginning of each line.</p>
<h4 id='others' class='heading'>Others</h4>
<ul>
<li><a href="https://github.com/kareman/testcommit/blob/master/Sources/main.swift">Test the latest commit (using make and/or Swift).</a></li>
<li><a href="http://blog.nottoobadsoftware.com/swiftshell/combine-markdown-files-and-convert-to-html-in-a-swift-script/">Run a shell command in the middle of a method chain</a>.</li>
<li><a href="http://blog.nottoobadsoftware.com/swiftshell/move-files-to-the-trash/">Move files to the trash</a>.</li>
</ul>
<h2 id='context' class='heading'>Context</h2>
<p>All commands (a.k.a. <a href="https://en.wikipedia.org/wiki/Process_(computing)">processes</a>) you run in SwiftShell need context: <a href="https://en.wikipedia.org/wiki/Environment_variable">environment variables</a>, the <a href="https://en.wikipedia.org/wiki/Working_directory">current working directory</a>, standard input, standard output and standard error (<a href="https://en.wikipedia.org/wiki/Standard_streams">standard streams</a>).</p>
<pre class="highlight swift"><code><span class="kd">public</span> <span class="kd">struct</span> <span class="kt">CustomContext</span><span class="p">:</span> <span class="kt">Context</span><span class="p">,</span> <span class="nf">CommandRunning</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">env</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">String</span><span class="p">]</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">currentdirectory</span><span class="p">:</span> <span class="kt">String</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">stdin</span><span class="p">:</span> <span class="kt">ReadableStream</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">stdout</span><span class="p">:</span> <span class="kt">WritableStream</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">stderror</span><span class="p">:</span> <span class="kt">WritableStream</span>
<span class="p">}</span>
</code></pre>
<p>You can create a copy of your application&rsquo;s context: <code>let context = CustomContext(main)</code>, or create a new empty one: <code>let context = CustomContext()</code>. Everything is mutable, so you can set e.g. the current directory or redirect standard error to a file.</p>
<h4 id='main-context' class='heading'>Main context</h4>
<p>The global variable <code><a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a></code> is the Context for the application itself. In addition to the properties mentioned above it also has these:</p>
<ul>
<li><code>public var encoding: String.Encoding</code>
The default encoding used when opening files or creating new streams.</li>
<li><code>public let tempdirectory: String</code>
A temporary directory you can use for temporary stuff.</li>
<li><code>public let arguments: [String]</code>
The arguments used when launching the application.</li>
<li><code>public let path: String</code>
The path to the application.</li>
</ul>
<p><code>main.stdout</code> is for normal output, like Swift&rsquo;s <code>print</code> function. <code>main.stderror</code> is for error output, and <code>main.stdin</code> is the standard input to your application, provided by something like <code>somecommand | yourapplication</code> in the terminal.</p>
<p>Commands can&rsquo;t change the context they run in (or anything else internally in your application) so e.g. <code>main.run(&quot;cd&quot;, &quot;somedirectory&quot;)</code> will achieve nothing. Use <code>main.currentdirectory = &quot;somedirectory&quot;</code> instead, this changes the current working directory for the entire application.</p>
<h4 id='example' class='heading'>Example</h4>
<p>Prepare a context similar to a new macOS user account&rsquo;s environment in the terminal (from <a href="https://github.com/kareman/testcommit/blob/master/Sources/main.swift">kareman/testcommit</a>):</p>
<pre class="highlight swift"><code><span class="kd">import</span> <span class="kt">SwiftShell</span>
<span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">extension</span> <span class="kt">Dictionary</span> <span class="k">where</span> <span class="kt">Key</span><span class="p">:</span><span class="nf">Hashable</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="n">filterToDictionary</span> <span class="o">&lt;</span><span class="kt">C</span><span class="p">:</span> <span class="kt">Collection</span><span class="o">&gt;</span> <span class="p">(</span><span class="nv">keys</span><span class="p">:</span> <span class="kt">C</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">[</span><span class="kt">Key</span><span class="p">:</span><span class="kt">Value</span><span class="p">]</span>
<span class="k">where</span> <span class="kt">C</span><span class="o">.</span><span class="kt">Iterator</span><span class="o">.</span><span class="kt">Element</span> <span class="o">==</span> <span class="kt">Key</span><span class="p">,</span> <span class="kt">C</span><span class="o">.</span><span class="kt">IndexDistance</span> <span class="o">==</span> <span class="nf">Int</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">result</span> <span class="o">=</span> <span class="p">[</span><span class="kt">Key</span><span class="p">:</span><span class="kt">Value</span><span class="p">](</span><span class="nv">minimumCapacity</span><span class="p">:</span> <span class="n">keys</span><span class="o">.</span><span class="n">count</span><span class="p">)</span>
<span class="k">for</span> <span class="n">key</span> <span class="k">in</span> <span class="nf">keys</span> <span class="p">{</span> <span class="n">result</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="k">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="p">}</span>
<span class="k">return</span> <span class="n">result</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Prepare an environment as close to a new OS X user account as possible.</span>
<span class="k">var</span> <span class="nv">cleanctx</span> <span class="o">=</span> <span class="nf">CustomContext</span><span class="p">(</span><span class="n">main</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">cleanenvvars</span> <span class="o">=</span> <span class="p">[</span><span class="s">"TERM_PROGRAM"</span><span class="p">,</span> <span class="s">"SHELL"</span><span class="p">,</span> <span class="s">"TERM"</span><span class="p">,</span> <span class="s">"TMPDIR"</span><span class="p">,</span> <span class="s">"Apple_PubSub_Socket_Render"</span><span class="p">,</span> <span class="s">"TERM_PROGRAM_VERSION"</span><span class="p">,</span> <span class="s">"TERM_SESSION_ID"</span><span class="p">,</span> <span class="s">"USER"</span><span class="p">,</span> <span class="s">"SSH_AUTH_SOCK"</span><span class="p">,</span> <span class="s">"__CF_USER_TEXT_ENCODING"</span><span class="p">,</span> <span class="s">"XPC_FLAGS"</span><span class="p">,</span> <span class="s">"XPC_SERVICE_NAME"</span><span class="p">,</span> <span class="s">"SHLVL"</span><span class="p">,</span> <span class="s">"HOME"</span><span class="p">,</span> <span class="s">"LOGNAME"</span><span class="p">,</span> <span class="s">"LC_CTYPE"</span><span class="p">,</span> <span class="s">"_"</span><span class="p">]</span>
<span class="n">cleanctx</span><span class="o">.</span><span class="n">env</span> <span class="o">=</span> <span class="n">cleanctx</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="nf">filterToDictionary</span><span class="p">(</span><span class="nv">keys</span><span class="p">:</span> <span class="n">cleanenvvars</span><span class="p">)</span>
<span class="n">cleanctx</span><span class="o">.</span><span class="n">env</span><span class="p">[</span><span class="s">"PATH"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"</span>
<span class="c1">// Create a temporary directory for testing.</span>
<span class="n">cleanctx</span><span class="o">.</span><span class="n">currentdirectory</span> <span class="o">=</span> <span class="n">main</span><span class="o">.</span><span class="n">tempdirectory</span>
</code></pre>
<h2 id='streams' class='heading'>Streams</h2>
<p>The protocols ReadableStream and WritableStream in <code><a href="Protocols/Context.html">Context</a></code> above can read and write text from/to commands, files or the application&rsquo;s own standard streams. They both have an <code>.encoding</code> property they use when encoding/decoding text.</p>
<p>You can use <code>let (input,output) = streams()</code> to create a new pair of streams. What you write to <code>input</code> you can read from <code>output</code>.</p>
<p><a href="https://github.com/kareman/FileSmith">FileSmith</a>&rsquo;s <a href="https://kareman.github.io/FileSmith/Classes/WritableFile.html">WritableFile</a> and <a href="https://kareman.github.io/FileSmith/Classes/ReadableFile.html">ReadableFile</a> are streams too, and can be used as stdin, stdout and stderror in SwiftShell Contexts, including <code><a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a></code>.</p>
<h4 id='writablestream' class='heading'>WritableStream</h4>
<p>When writing to a WritableStream you normally use <code>.print</code> which works exactly like Swift&rsquo;s built-in print function:</p>
<pre class="highlight swift"><code><span class="n">main</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="nf">print</span><span class="p">(</span><span class="s">"everything is fine"</span><span class="p">)</span>
<span class="n">main</span><span class="o">.</span><span class="n">stderror</span><span class="o">.</span><span class="nf">print</span><span class="p">(</span><span class="s">"no wait, something went wrong ..."</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">writefile</span> <span class="o">=</span> <span class="k">try</span> <span class="nf">open</span><span class="p">(</span><span class="nv">forWriting</span><span class="p">:</span> <span class="n">path</span><span class="p">)</span> <span class="c1">// WritableStream</span>
<span class="n">writefile</span><span class="o">.</span><span class="nf">print</span><span class="p">(</span><span class="s">"1"</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="o">/</span><span class="mi">5</span><span class="p">,</span> <span class="nv">separator</span><span class="p">:</span> <span class="s">"+"</span><span class="p">,</span> <span class="nv">terminator</span><span class="p">:</span> <span class="s">"="</span><span class="p">)</span>
</code></pre>
<p>If you want to be taken literally, use <code>.write</code> instead. It doesn&rsquo;t add a newline and writes exactly and only what you write:</p>
<pre class="highlight swift"><code><span class="n">writefile</span><span class="o">.</span><span class="nf">write</span><span class="p">(</span><span class="s">"Read my lips:"</span><span class="p">)</span>
</code></pre>
<p>You can close the stream, so anyone who tries to read from the other end won&rsquo;t have to wait around forever:</p>
<pre class="highlight swift"><code><span class="n">writefile</span><span class="o">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre>
<h4 id='readablestream' class='heading'>ReadableStream</h4>
<p>When reading from a ReadableStream you can read everything at once:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">readfile</span> <span class="o">=</span> <span class="k">try</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="c1">// ReadableStream</span>
<span class="k">let</span> <span class="nv">contents</span> <span class="o">=</span> <span class="n">readfile</span><span class="o">.</span><span class="nf">read</span><span class="p">()</span>
</code></pre>
<p>This will read everything and wait for the stream to be closed if it isn&rsquo;t already.</p>
<p>You can also read it asynchronously, that is read whatever is in there now and continue without waiting for it to be closed:</p>
<pre class="highlight swift"><code><span class="k">while</span> <span class="k">let</span> <span class="nv">text</span> <span class="o">=</span> <span class="n">main</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="nf">readSome</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// do something with text...</span>
<span class="p">}</span>
</code></pre>
<p><code>.readSome()</code> returns <code>String?</code> - if there is anything there it returns it, if the stream is closed it returns nil, and if there is nothing there and the stream is still open it will wait until either there is more content or the stream is closed.</p>
<p>Another way to read asynchronously is to use the <code>lines</code> method which creates a lazy sequence of Strings, one for each line in the stream:</p>
<pre class="highlight swift"><code><span class="k">for</span> <span class="n">line</span> <span class="k">in</span> <span class="n">main</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="nf">lines</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre>
<p>Or instead of stopping and waiting for any output you can be notified whenever there is something in the stream:</p>
<pre class="highlight swift"><code><span class="n">main</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="nf">onOutput</span> <span class="p">{</span> <span class="n">stream</span> <span class="k">in</span>
<span class="c1">// stream refers to main.stdin</span>
<span class="p">}</span>
</code></pre>
<h4 id='data' class='heading'>Data</h4>
<p>In addition to text, streams can also handle raw Data:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">data</span> <span class="o">=</span> <span class="nf">Data</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">writer</span><span class="o">.</span><span class="nf">write</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="n">data</span><span class="p">)</span>
<span class="n">reader</span><span class="o">.</span><span class="nf">readSomeData</span><span class="p">()</span>
<span class="n">reader</span><span class="o">.</span><span class="nf">readData</span><span class="p">()</span>
</code></pre>
<h2 id='commands' class='heading'>Commands</h2>
<p>All Contexts (<code><a href="Structs/CustomContext.html">CustomContext</a></code> and <code><a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a></code>) implement <code><a href="Protocols/CommandRunning.html">CommandRunning</a></code>, which means they can run commands using themselves as the Context. ReadableStream and String can also run commands, they use <code><a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a></code> as the Context and themselves as <code>.stdin</code>. As a shortcut you can just use <code><a href="Functions.html#/s:10SwiftShell3runAA9RunOutputCSS4bash_Sb07combineE0tF">run(...)</a></code> instead of <code>main.run(...)</code></p>
<p>There are three different ways of running a command:</p>
<h4 id='run' class='heading'>Run</h4>
<p>The simplest is to just run the command, wait until it&rsquo;s finished and return the results:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">result1</span> <span class="o">=</span> <span class="nf">run</span><span class="p">(</span><span class="s">"/usr/bin/executable"</span><span class="p">,</span> <span class="s">"argument1"</span><span class="p">,</span> <span class="s">"argument2"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">result2</span> <span class="o">=</span> <span class="nf">run</span><span class="p">(</span><span class="s">"executable"</span><span class="p">,</span> <span class="s">"argument1"</span><span class="p">,</span> <span class="s">"argument2"</span><span class="p">)</span>
</code></pre>
<p>If you don&rsquo;t provide the full path to the executable, then SwiftShell will try to find it in any of the directories in the <code>PATH</code> environment variable.</p>
<p><code>run</code> returns the following information:</p>
<pre class="highlight swift"><code><span class="c1">/// Output from a `run` command.</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nf">RunOutput</span> <span class="p">{</span>
<span class="c1">/// The error from running the command, if any.</span>
<span class="k">let</span> <span class="nv">error</span><span class="p">:</span> <span class="kt">CommandError</span><span class="p">?</span>
<span class="c1">/// Standard output, trimmed for whitespace and newline if it is single-line.</span>
<span class="k">let</span> <span class="nv">stdout</span><span class="p">:</span> <span class="kt">String</span>
<span class="c1">/// Standard error, trimmed for whitespace and newline if it is single-line.</span>
<span class="k">let</span> <span class="nv">stderror</span><span class="p">:</span> <span class="kt">String</span>
<span class="c1">/// The exit code of the command. Anything but 0 means there was an error.</span>
<span class="k">let</span> <span class="nv">exitcode</span><span class="p">:</span> <span class="kt">Int</span>
<span class="c1">/// Checks if the exit code is 0.</span>
<span class="k">let</span> <span class="nv">succeeded</span><span class="p">:</span> <span class="kt">Bool</span>
<span class="p">}</span>
</code></pre>
<p>For example:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">date</span> <span class="o">=</span> <span class="nf">run</span><span class="p">(</span><span class="s">"date"</span><span class="p">,</span> <span class="s">"-u"</span><span class="p">)</span><span class="o">.</span><span class="n">stdout</span>
<span class="nf">print</span><span class="p">(</span><span class="s">"Today's date in UTC is "</span> <span class="o">+</span> <span class="n">date</span><span class="p">)</span>
</code></pre>
<h4 id='print-output' class='heading'>Print output</h4>
<pre class="highlight swift"><code><span class="k">try</span> <span class="nf">runAndPrint</span><span class="p">(</span><span class="s">"executable"</span><span class="p">,</span> <span class="s">"arg"</span><span class="p">)</span>
</code></pre>
<p>This runs a command like in the terminal, where any output goes to the Context&rsquo;s (<code><a href="Global Variables.html#/s:10SwiftShell4mainAA11MainContextCv">main</a></code> in this case) <code>.stdout</code> and <code>.stderror</code> respectively. If the executable could not be found, was inaccessible or not executable, or the command returned with an exit code other than zero, then <code>runAndPrint</code> will throw a <code><a href="Enums/CommandError.html">CommandError</a></code>.</p>
<p>The name may seem a bit cumbersome, but it explains exactly what it does. SwiftShell never prints anything without explicitly being told to.</p>
<h4 id='asynchronous' class='heading'>Asynchronous</h4>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">command</span> <span class="o">=</span> <span class="nf">runAsync</span><span class="p">(</span><span class="s">"cmd"</span><span class="p">,</span> <span class="s">"-n"</span><span class="p">,</span> <span class="mi">245</span><span class="p">)</span><span class="o">.</span><span class="nf">onCompletion</span> <span class="p">{</span> <span class="n">command</span> <span class="k">in</span>
<span class="c1">// be notified when the command is finished.</span>
<span class="p">}</span>
<span class="n">command</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="nf">onOutput</span> <span class="p">{</span> <span class="n">stdout</span> <span class="k">in</span>
<span class="c1">// be notified when the command produces output. </span>
<span class="p">}</span>
<span class="c1">// do something with command while it is still running.</span>
<span class="k">try</span> <span class="n">command</span><span class="o">.</span><span class="nf">finish</span><span class="p">()</span> <span class="c1">// wait for it to finish.</span>
</code></pre>
<p><code>runAsync</code> launches a command and continues before it&rsquo;s finished. It returns this:</p>
<pre class="highlight swift"><code><span class="c1">/// Output from the 'runAsync' methods.</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nf">AsyncCommand</span> <span class="p">{</span>
<span class="kd">public</span> <span class="k">let</span> <span class="nv">stdout</span><span class="p">:</span> <span class="kt">ReadableStream</span>
<span class="kd">public</span> <span class="k">let</span> <span class="nv">stderror</span><span class="p">:</span> <span class="kt">ReadableStream</span>
<span class="c1">/// Is the command still running?</span>
<span class="kd">public</span> <span class="k">var</span> <span class="nv">isRunning</span><span class="p">:</span> <span class="kt">Bool</span>
<span class="c1">/// Terminates command.</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">stop</span><span class="p">()</span>
<span class="c1">/// Waits for command to finish.</span>
<span class="c1">/// - returns: itself</span>
<span class="c1">/// - throws: `CommandError.returnedErrorCode(command: String, errorcode: Int)` if the exit code is anything but 0.</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">finish</span><span class="p">()</span> <span class="k">throws</span> <span class="o">-&gt;</span> <span class="kt">AsyncCommand</span>
<span class="c1">/// Waits for command to finish, then returns with exit code.</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">exitcode</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Int</span>
<span class="c1">/// Takes a closure to be called when the command has finished.</span>
<span class="c1">/// - Parameter handler: A closure taking this AsyncCommand as input, returning nothing.</span>
<span class="c1">/// - Returns: This AsyncCommand.</span>
<span class="kd">public</span> <span class="kd">func</span> <span class="nf">onCompletion</span><span class="p">(</span><span class="n">_</span> <span class="nv">handler</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">(</span><span class="kt">AsyncCommand</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Void</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">AsyncCommand</span>
<span class="p">}</span>
</code></pre>
<p>You can process standard output and standard error, and optionally wait until it&rsquo;s finished and handle any errors.</p>
<p>If you read all of command.stderror or command.stdout it will automatically wait for the command to close its streams (and presumably finish running). You can still call <code>finish()</code> to check for errors.</p>
<h4 id='parameters' class='heading'>Parameters</h4>
<p>The 3 <code>run</code> functions above take 2 different types of parameters:</p>
<h5 id='_-executable-string-_-args-any' class='heading'>(_ executable: String, _ args: Any &hellip;)</h5>
<p>If the path to the executable is without any <code>/</code>, SwiftShell will try to find the full path using the <code>which</code> shell command, which searches the directories in the <code>PATH</code> environment variable in order.</p>
<p>The array of arguments can contain any type, since everything is convertible to strings in Swift. If it contains any arrays it will be flattened so only the elements will be used, not the arrays themselves.</p>
<pre class="highlight swift"><code><span class="k">try</span> <span class="nf">runAndPrint</span><span class="p">(</span><span class="s">"echo"</span><span class="p">,</span> <span class="s">"We are"</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="s">"arguments"</span><span class="p">)</span>
<span class="c1">// echo "We are" 4 arguments</span>
<span class="k">let</span> <span class="nv">array</span> <span class="o">=</span> <span class="p">[</span><span class="s">"But"</span><span class="p">,</span> <span class="s">"we"</span><span class="p">,</span> <span class="s">"are"</span><span class="p">]</span>
<span class="k">try</span> <span class="nf">runAndPrint</span><span class="p">(</span><span class="s">"echo"</span><span class="p">,</span> <span class="n">array</span><span class="p">,</span> <span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"arguments"</span><span class="p">)</span>
<span class="c1">// echo But we are 5 arguments</span>
</code></pre>
<h5 id='bash-bashcommand-string' class='heading'>(bash bashcommand: String)</h5>
<p>These are the commands you normally use in the Terminal. You can use pipes and redirection and all that good stuff:</p>
<pre class="highlight swift"><code><span class="k">try</span> <span class="nf">runAndPrint</span><span class="p">(</span><span class="nv">bash</span><span class="p">:</span> <span class="s">"cmd1 arg1 | cmd2 &gt; output.txt"</span><span class="p">)</span>
</code></pre>
<p>Note that you can achieve the same thing in pure SwiftShell, though nowhere near as succinctly:</p>
<pre class="highlight swift"><code><span class="k">var</span> <span class="nv">file</span> <span class="o">=</span> <span class="k">try</span> <span class="nf">open</span><span class="p">(</span><span class="nv">forWriting</span><span class="p">:</span> <span class="s">"output.txt"</span><span class="p">)</span>
<span class="nf">runAsync</span><span class="p">(</span><span class="s">"cmd1"</span><span class="p">,</span> <span class="s">"arg1"</span><span class="p">)</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="nf">runAsync</span><span class="p">(</span><span class="s">"cmd2"</span><span class="p">)</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="nf">write</span><span class="p">(</span><span class="nv">to</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">file</span><span class="p">)</span>
</code></pre>
<h4 id='errors' class='heading'>Errors</h4>
<p>If the command provided to <code>runAsync</code> could not be launched for any reason the program will print the error to standard error and exit, as is usual in scripts. The <code>runAsync(&quot;cmd&quot;).finish()</code> method throws an error if the exit code of the command is anything but 0:</p>
<pre class="highlight swift"><code><span class="k">let</span> <span class="nv">command</span> <span class="o">=</span> <span class="nf">runAsync</span><span class="p">(</span><span class="s">"cmd"</span><span class="p">,</span> <span class="s">"-n"</span><span class="p">,</span> <span class="mi">245</span><span class="p">)</span>
<span class="c1">// do something with command.stderror or command.stdoutCommandError</span>
<span class="nf">do</span> <span class="p">{</span>
<span class="k">try</span> <span class="n">command</span><span class="o">.</span><span class="nf">finish</span><span class="p">()</span>
<span class="p">}</span> <span class="k">catch</span> <span class="kt">CommandError</span><span class="o">.</span><span class="nf">ReturnedErrorCode</span><span class="p">(</span><span class="k">let</span> <span class="nv">error</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// use error.command or error.errorcode</span>
<span class="p">}</span>
</code></pre>
<p>The <code>runAndPrint</code> command can also throw this error, in addition to this one if the command could not be launched:</p>
<pre class="highlight swift"><code><span class="p">}</span> <span class="k">catch</span> <span class="kt">CommandError</span><span class="o">.</span><span class="nf">InAccessibleExecutable</span><span class="p">(</span><span class="k">let</span> <span class="nv">path</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// path is the full path to the executable</span>
<span class="p">}</span>
</code></pre>
<p>Instead of dealing with the values from these errors you can just print them:</p>
<pre class="highlight swift"><code><span class="p">}</span> <span class="nf">catch</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>&hellip; or if they are sufficiently serious you can print them to standard error and exit:</p>
<pre class="highlight swift"><code><span class="p">}</span> <span class="nf">catch</span> <span class="p">{</span>
<span class="nf">exit</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>When at the top code level you don&rsquo;t need to catch any errors, but you still have to use <code>try</code>.</p>
<h2 id='setup' class='heading'>Setup</h2>
<h3 id='stand-alone-project' class='heading'>Stand-alone project</h3>
<p>If you put <a href="https://raw.githubusercontent.com/kareman/SwiftShell/master/Misc/swiftshell-init">Misc/swiftshell-init</a> somewhere in your $PATH you can create a new project with <code>swiftshell-init &lt;name&gt;</code>. This creates a new folder, initialises a Swift Package Manager executable folder structure, downloads the latest version of SwiftShell, creates an Xcode project and opens it. After running <code>swift build</code> you can find the compiled executable at <code>.build/debug/&lt;name&gt;</code>.</p>
<h3 id='script-file-using-a-href-https-github-com-johnsundell-marathon-marathon-a' class='heading'>Script file using <a href="https://github.com/JohnSundell/Marathon">Marathon</a></h3>
<p>First add SwiftShell to Marathon: </p>
<pre class="highlight shell"><code>marathon add https://github.com/kareman/SwiftShell.git
</code></pre>
<p>Then run your Swift scripts with <code>marathon run &lt;name&gt;.swift</code>. Or add <code>#!/usr/bin/env marathon run</code> to the top of every script file and run them with <code>./&lt;name&gt;.swift</code>.</p>
<h3 id='a-href-https-github-com-apple-swift-package-manager-swift-package-manager-a' class='heading'><a href="https://github.com/apple/swift-package-manager">Swift Package Manager</a></h3>
<p>Add <code>.package(url: &quot;https://github.com/kareman/SwiftShell&quot;, from: &quot;4.0.0&quot;)</code> to your Package.swift:</p>
<pre class="highlight swift"><code><span class="c1">// swift-tools-version:4.0</span>
<span class="c1">// The swift-tools-version declares the minimum version of Swift required to build this package.</span>
<span class="kd">import</span> <span class="kt">PackageDescription</span>
<span class="k">let</span> <span class="nv">package</span> <span class="o">=</span> <span class="nf">Package</span><span class="p">(</span>
<span class="nv">name</span><span class="p">:</span> <span class="s">"ProjectName"</span><span class="p">,</span>
<span class="nv">dependencies</span><span class="p">:</span> <span class="p">[</span>
<span class="c1">// Dependencies declare other packages that this package depends on.</span>
<span class="o">.</span><span class="nf">package</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="s">"https://github.com/kareman/SwiftShell"</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="s">"4.0.0"</span><span class="p">)</span>
<span class="p">],</span>
<span class="nv">targets</span><span class="p">:</span> <span class="p">[</span>
<span class="c1">// Targets are the basic building blocks of a package. A target can define a module or a test suite.</span>
<span class="c1">// Targets can depend on other targets in this package, and on products in packages which this package depends on.</span>
<span class="o">.</span><span class="nf">target</span><span class="p">(</span>
<span class="nv">name</span><span class="p">:</span> <span class="s">"ProjectName"</span><span class="p">,</span>
<span class="nv">dependencies</span><span class="p">:</span> <span class="p">[</span><span class="s">"SwiftShell"</span><span class="p">]),</span>
<span class="p">]</span>
<span class="p">)</span>
</code></pre>
<p>and run <code>swift build</code>.</p>
<h3 id='a-href-https-github-com-carthage-carthage-carthage-a' class='heading'><a href="https://github.com/Carthage/Carthage">Carthage</a></h3>
<p>Add <code>github &quot;kareman/SwiftShell&quot; &gt;= 4.0</code> to your Cartfile, then run <code>carthage update</code> and add the resulting framework to the <q>Embedded Binaries</q> section of the application. See <a href="https://github.com/Carthage/Carthage#adding-frameworks-to-an-application">Carthage&rsquo;s README</a> for further instructions.</p>
<h3 id='a-href-https-cocoapods-org-cocoapods-a' class='heading'><a href="https://cocoapods.org/">CocoaPods</a></h3>
<p>Add <code>SwiftShell</code> to your <code>Podfile</code>.</p>
<pre class="highlight plaintext"><code>pod 'SwiftShell', '&gt;= 4.0.0'
</code></pre>
<p>Then run <code>pod install</code> to install it.</p>
<h2 id='license' class='heading'>License</h2>
<p>Released under the MIT License (MIT), <a href="http://opensource.org/licenses/MIT">http://opensource.org/licenses/MIT</a></p>
<p>Kåre Morstøl, <a href="http://nottoobadsoftware.com">NotTooBad Software</a></p>
</section>
</section>
<section id="footer">
<p>&copy; 2018 <a class="link" href="" target="_blank" rel="external">kareman</a>. All rights reserved. (Last updated: 2018-03-04)</p>
<p>Generated by <a class="link" href="https://github.com/realm/jazzy" target="_blank" rel="external">jazzy ♪♫ v0.9.1</a>, a <a class="link" href="http://realm.io" target="_blank" rel="external">Realm</a> project.</p>
</section>
</article>
</div>
</body>
</div>
</html>