├── .github
├── FUNDING.yml
└── workflows
│ ├── ci.yml
│ └── homebrew.yml
├── .gitignore
├── .travis.yml
├── Examples
├── README.md
├── async-main-count-lines
├── ink
└── terminal-rainbow
├── LICENSE.md
├── Package.resolved
├── Package.swift
├── Package@swift-5.3.swift
├── README.md
├── Sources
├── Command
│ ├── CommandLine.usage.swift
│ ├── clean().swift
│ ├── edit().swift
│ ├── editor().swift
│ ├── eject().swift
│ ├── run().Input.swift
│ └── run().swift
├── Script
│ ├── Constraint.swift
│ ├── DependencyName.swift
│ ├── ExecutableTargetMainStyle.swift
│ ├── ImportSpecification.swift
│ ├── Script.swift
│ └── parse().swift
├── Utility
│ ├── Path+ResolvedHash.swift
│ ├── Process+1up.swift
│ ├── TemporaryDirectory.swift
│ ├── etc.swift
│ └── exec().swift
├── main.swift
└── swift-sh-edit
│ └── main.swift
├── Tests
├── All
│ ├── ImportSpecificationUnitTests.swift
│ ├── IntegrationTests.swift
│ ├── ModeUnitTests.swift
│ ├── UtilityTests.swift
│ └── XCTestManifests.swift
└── LinuxMain.swift
└── tea.yaml
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: mxcl
2 | patreon: mxcl
3 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | pull_request:
4 | paths:
5 | - '**.swift'
6 | - .github/workflows/ci.yml
7 | schedule:
8 | - cron: '3 3 * * 0' # 3:03 AM, every Sunday
9 | jobs:
10 | macOS:
11 | runs-on: ${{ matrix.cfg.macos }}
12 | strategy:
13 | matrix:
14 | cfg:
15 | - swift: 5.5
16 | macos: macos-12
17 | - swift: 5.6
18 | macos: macos-12
19 | - swift: 5.7
20 | macos: macos-12
21 | - swift: ~5.8
22 | macos: macos-14
23 | - swift: ~5.9
24 | macos: macos-14
25 | - swift: ~5.10
26 | macos: macos-14
27 | # - swift: ~6.0
28 | # macos: macos-14
29 | steps:
30 | - uses: actions/checkout@v4
31 | - uses: mxcl/xcodebuild@v3
32 | with:
33 | swift: ${{ matrix.cfg.swift }}
34 | linux:
35 | runs-on: ubuntu-20.04
36 | strategy:
37 | matrix:
38 | swift:
39 | # - 5.1.5 # requires ubuntu 18.04
40 | - 5.2.5
41 | - 5.3.3
42 | - 5.4.3
43 | - 5.5.3
44 | - 5.6.3
45 | - 5.7.3
46 | - 5.8.1
47 | - 5.9.2
48 | - 5.10.1
49 | steps:
50 | - uses: actions/checkout@v4
51 | - uses: YOCKOW/Action-setup-swift@v1
52 | with:
53 | swift-version: ${{ matrix.swift }}
54 | - run: swift test -Xswiftc -suppress-warnings --enable-test-discovery
55 |
--------------------------------------------------------------------------------
/.github/workflows/homebrew.yml:
--------------------------------------------------------------------------------
1 | name: Homebrew Bump Formula
2 | on:
3 | release:
4 | types: [published]
5 | jobs:
6 | core:
7 | runs-on: macos-latest
8 | steps:
9 | - uses: dawidd6/action-homebrew-bump-formula@v3
10 | with:
11 | token: ${{ secrets.PAT }}
12 | formula: swift-sh
13 | mxcl:
14 | runs-on: macos-latest
15 | steps:
16 | - uses: dawidd6/action-homebrew-bump-formula@v3
17 | with:
18 | tap: mxcl/homebrew-made
19 | token: ${{ secrets.PAT }}
20 | formula: swift-sh
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /swift-sh.xcodeproj
2 | /sync
3 | /.swiftpm
4 | /.build
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os: osx
2 | language: swift
3 |
4 | if: type = pull_request
5 |
6 | jobs:
7 | include:
8 | - osx_image: xcode11.3 # macOS 10.14.6
9 | - osx_image: xcode12.2 # macOS 10.15.7
10 | - osx_image: xcode12.3 # macOS 11.1
11 | - osx_image: xcode12.4 # macOS 11.2.1
12 | - osx_image: xcode12.5 # macOS 11.3
13 |
14 | script: swift test --enable-test-discovery
15 |
--------------------------------------------------------------------------------
/Examples/README.md:
--------------------------------------------------------------------------------
1 | * [Single-script Webserver](https://github.com/cak/server.swift/blob/master/server.swift)
2 | * [Delete tweets](https://gist.github.com/mxcl/002c3514d50b73287c89268c45662394)
3 | * [Terminal Rainbow](terminal-rainbow)
4 | * [Ink example](ink)
5 |
6 | Add your script here via PR.
7 |
--------------------------------------------------------------------------------
/Examples/async-main-count-lines:
--------------------------------------------------------------------------------
1 | #!/user/bin/swift sh
2 | import Foundation
3 | import ArgumentParser // apple/swift-argument-parser ~> 1.4.0
4 |
5 | /// example borrowed from [here](https://swiftpackageindex.com/apple/swift-argument-parser/1.4.0/documentation/argumentparser/asyncparsablecommand)
6 | @main
7 | struct CountLines: AsyncParsableCommand {
8 | @Argument(transform: URL.init(fileURLWithPath:))
9 | var inputFile: URL
10 | mutating func run() async throws {
11 | let fileHandle = try FileHandle(forReadingFrom: inputFile)
12 | let lineCount = try await fileHandle.bytes.lines.reduce(into: 0)
13 | { count, _ in count += 1 }
14 | print(lineCount)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Examples/ink:
--------------------------------------------------------------------------------
1 | #!/usr/bin/swift sh
2 |
3 | import Ink // @JohnSundell == 0.5.0
4 |
5 | let markdown = """
6 | # Ink parses markdown and renders to HTML
7 | ## Features
8 | - header blocks
9 | - list blocks
10 | - nested list
11 | - Character styles
12 | - *italic*
13 | - **bold**
14 | - ~~strikethrough~~
15 |
16 | ## HTML output:
17 |
18 |
19 | """
20 | let html = MarkdownParser().html(from: markdown)
21 | print(markdown)
22 | print(html)
23 |
--------------------------------------------------------------------------------
/Examples/terminal-rainbow:
--------------------------------------------------------------------------------
1 | #!/usr/bin/swift sh
2 | import Foundation
3 | import Chalk // @mxcl == 0.4.0
4 |
5 | extension Int {
6 | var fg: UInt8 {
7 | if !(16..<250 ~= self) || 24...36 ~= (self - 16) % 36 {
8 | return 16
9 | } else {
10 | return 255
11 | }
12 | }
13 | var bg: UInt8 {
14 | return UInt8(self)
15 | }
16 | var paddedString: String {
17 | return " \(self)".padding(toLength: 5, withPad: " ", startingAt: 0)
18 | }
19 | var terminator: String {
20 | return (self + 3).isMultiple(of: 6) ? "\n" : ""
21 | }
22 | }
23 |
24 | for x in 0...255 {
25 | print("\(x.paddedString, color: .extended(x.fg), background: .extended(x.bg))", terminator: x.terminator)
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Unlicense (Public Domain)
2 | ============================
3 |
4 | This is free and unencumbered software released into the public domain.
5 |
6 | Anyone is free to copy, modify, publish, use, compile, sell, or
7 | distribute this software, either in source code form or as a compiled
8 | binary, for any purpose, commercial or non-commercial, and by any
9 | means.
10 |
11 | In jurisdictions that recognize copyright laws, the author or authors
12 | of this software dedicate any and all copyright interest in the
13 | software to the public domain. We make this dedication for the benefit
14 | of the public at large and to the detriment of our heirs and
15 | successors. We intend this dedication to be an overt act of
16 | relinquishment in perpetuity of all present and future rights to this
17 | software under copyright law.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | For more information, please refer to <>
28 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "AEXML",
6 | "repositoryURL": "https://github.com/tadija/AEXML.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3",
10 | "version": "4.6.1"
11 | }
12 | },
13 | {
14 | "package": "CryptoSwift",
15 | "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift",
16 | "state": {
17 | "branch": null,
18 | "revision": "4b0565384d3c4c588af09e660535b2c7c9bf5b39",
19 | "version": "1.4.2"
20 | }
21 | },
22 | {
23 | "package": "LegibleError",
24 | "repositoryURL": "https://github.com/mxcl/LegibleError",
25 | "state": {
26 | "branch": null,
27 | "revision": "3aeb15455edc0cd6ea0e8d562079db4ab9a25afc",
28 | "version": "1.0.5"
29 | }
30 | },
31 | {
32 | "package": "Path.swift",
33 | "repositoryURL": "https://github.com/mxcl/Path.swift",
34 | "state": {
35 | "branch": null,
36 | "revision": "9c6f807b0a76be0e27aecc908bc6f173400d839e",
37 | "version": "1.4.0"
38 | }
39 | },
40 | {
41 | "package": "PathKit",
42 | "repositoryURL": "https://github.com/kylef/PathKit.git",
43 | "state": {
44 | "branch": null,
45 | "revision": "3bfd2737b700b9a36565a8c94f4ad2b050a5e574",
46 | "version": "1.0.1"
47 | }
48 | },
49 | {
50 | "package": "Spectre",
51 | "repositoryURL": "https://github.com/kylef/Spectre.git",
52 | "state": {
53 | "branch": null,
54 | "revision": "26cc5e9ae0947092c7139ef7ba612e34646086c7",
55 | "version": "0.10.1"
56 | }
57 | },
58 | {
59 | "package": "StreamReader",
60 | "repositoryURL": "https://github.com/mxcl/StreamReader",
61 | "state": {
62 | "branch": null,
63 | "revision": "0cabaa9d539037da1b25b8cbe58a8ecafaedea67",
64 | "version": "1.0.1"
65 | }
66 | },
67 | {
68 | "package": "Version",
69 | "repositoryURL": "https://github.com/mxcl/Version",
70 | "state": {
71 | "branch": null,
72 | "revision": "1fe824b80d89201652e7eca7c9252269a1d85e25",
73 | "version": "2.0.1"
74 | }
75 | },
76 | {
77 | "package": "XcodeProj",
78 | "repositoryURL": "https://github.com/tuist/xcodeproj",
79 | "state": {
80 | "branch": null,
81 | "revision": "446f3a0db73e141c7f57e26fcdb043096b1db52c",
82 | "version": "8.3.1"
83 | }
84 | }
85 | ]
86 | },
87 | "version": 1
88 | }
89 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "swift-sh",
6 | platforms: [
7 | .macOS(.v10_12)
8 | ],
9 | products: [
10 | .executable(name: "swift-sh", targets: ["swift-sh"]),
11 | .library(name: "Script", targets: ["Script"]),
12 | .library(name: "Utility", targets: ["Utility"]),
13 | .library(name: "Command", targets: ["Command"]),
14 | ],
15 | dependencies: [
16 | .package(url: "https://github.com/mxcl/Path.swift", from: "1.0.1"),
17 | .package(url: "https://github.com/mxcl/StreamReader", from: "1.0.0"),
18 | .package(url: "https://github.com/mxcl/LegibleError", from: "1.0.0"),
19 | .package(url: "https://github.com/mxcl/Version", from: "2.0.0"),
20 | .package(url: "https://github.com/krzyzanowskim/CryptoSwift", "1.3.0"..<"1.4.0"),
21 | ],
22 | targets: [
23 | .target(
24 | name: "swift-sh",
25 | dependencies: ["Command", "LegibleError"],
26 | path: "Sources",
27 | exclude: ["Script", "Utility", "Command", "swift-sh-edit"],
28 | sources: ["main.swift"]),
29 | .target(
30 | name: "Script",
31 | dependencies: ["Utility", "StreamReader"]),
32 | .target(
33 | name: "Utility",
34 | dependencies: [
35 | .product(name: "Path", package: "Path.swift"),
36 | "Version",
37 | "CryptoSwift"
38 | ]),
39 | .target(
40 | name: "Command",
41 | dependencies: ["Script"]),
42 | .testTarget(
43 | name: "All",
44 | dependencies: ["swift-sh"]),
45 | ]
46 | )
47 |
48 | #if os(macOS)
49 | package.products.append(.executable(name: "swift-sh-edit", targets: ["swift-sh-edit"]))
50 | package.targets.append(.target(name: "swift-sh-edit", dependencies: ["XcodeProj", "Utility"]))
51 | package.dependencies.append(.package(url: "https://github.com/tuist/xcodeproj", from: "7.0.0"))
52 | #endif
53 |
--------------------------------------------------------------------------------
/Package@swift-5.3.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "swift-sh",
6 | platforms: [
7 | .macOS(.v10_12)
8 | ],
9 | products: [
10 | .executable(name: "swift-sh", targets: ["swift-sh"]),
11 | .library(name: "Script", targets: ["Script"]),
12 | .library(name: "Utility", targets: ["Utility"]),
13 | .library(name: "Command", targets: ["Command"]),
14 | ],
15 | dependencies: [
16 | .package(url: "https://github.com/mxcl/Path.swift", from: "1.0.1"),
17 | .package(url: "https://github.com/mxcl/StreamReader", from: "1.0.0"),
18 | .package(url: "https://github.com/mxcl/LegibleError", from: "1.0.0"),
19 | .package(url: "https://github.com/mxcl/Version", from: "2.0.0"),
20 | .package(url: "https://github.com/krzyzanowskim/CryptoSwift", from: "1.4.2"),
21 | ],
22 | targets: [
23 | .target(
24 | name: "swift-sh",
25 | dependencies: ["Command", "LegibleError"],
26 | path: "Sources",
27 | exclude: ["Script", "Utility", "Command", "swift-sh-edit"],
28 | sources: ["main.swift"]),
29 | .target(
30 | name: "Script",
31 | dependencies: ["Utility", "StreamReader"]),
32 | .target(
33 | name: "Utility",
34 | dependencies: [
35 | .product(name: "Path", package: "Path.swift"),
36 | "Version",
37 | "CryptoSwift"
38 | ]),
39 | .target(
40 | name: "Command",
41 | dependencies: ["Script"]),
42 | .testTarget(
43 | name: "All",
44 | dependencies: ["swift-sh"]),
45 | ]
46 | )
47 |
48 | #if os(macOS)
49 | package.products.append(.executable(name: "swift-sh-edit", targets: ["swift-sh-edit"]))
50 | package.targets.append(.target(name: "swift-sh-edit", dependencies: ["XcodeProj", "Utility"]))
51 | package.dependencies.append(.package(name: "XcodeProj", url: "https://github.com/tuist/xcodeproj", from: "8.3.1"))
52 | #endif
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # `swift sh` ![badge-platforms] ![badge-languages] [](https://travis-ci.com/mxcl/swift-sh)
2 |
3 | Writing Swift scripts is *easy*:
4 |
5 | ```sh
6 | $ cat < script
7 | #!/usr/bin/swift
8 | print("Hi!")
9 | EOF
10 | $ chmod u+x script
11 | $ ./script
12 | Hi!
13 | ```
14 |
15 | Sadly, to use third-party dependencies we have to migrate our script to a swift
16 | package and use `swift build`, a relatively heavy solution when all we wanted
17 | was to whip up a quick script. `swift-sh` gives us the best of both worlds:
18 |
19 | ```sh
20 | $ cat < script
21 | #!/usr/bin/swift sh
22 | import PromiseKit // @mxcl ~> 6.5
23 | print(Promise.value("Hi!"))
24 | EOF
25 | $ chmod u+x script
26 | $ ./script
27 | Promise("Hi!")
28 | ```
29 |
30 | In case it’s not clear, `swift-sh` reads the comment after the `import` and
31 | uses this information to fetch your dependencies.
32 |
33 | ---
34 |
35 | Let’s work through an example: if you had a *single file* called `foo.swift`
36 | and you wanted to import [mxcl/PromiseKit](https://github.com/mxcl/PromiseKit):
37 |
38 | ```swift
39 | #!/usr/bin/swift sh
40 |
41 | import Foundation
42 | import PromiseKit // @mxcl ~> 6.5
43 |
44 | firstly {
45 | after(.seconds(2))
46 | }.then {
47 | after(.milliseconds(500))
48 | }.done {
49 | print("notice: two and a half seconds elapsed")
50 | exit(0)
51 | }
52 |
53 | RunLoop.main.run()
54 | ```
55 |
56 | You could run it with:
57 |
58 | ```
59 | $ swift sh foo.swift
60 | ```
61 |
62 | Or to make it more “scripty”, first make it executable:
63 |
64 | ```
65 | $ chmod u+x foo.swift
66 | $ mv foo.swift foo # optional step!
67 | ```
68 |
69 | And then run it directly:
70 |
71 | ```
72 | $ ./foo
73 | ```
74 |
75 | # Sponsorship
76 |
77 | If your company depends on `swift-sh` please consider sponsoring the project.
78 | Otherwise it is hard for me to justify maintaining it.
79 |
80 | # Installation
81 |
82 | ```
83 | brew install swift-sh
84 | ```
85 |
86 | Or you can build manually using `swift build`.
87 |
88 | Installation results in a single executable called `swift-sh`, the `swift`
89 | executable will call this (provided it is in your `PATH`) when you type:
90 | `swift sh`.
91 |
92 | We actively support both Linux and Mac and will support Windows as soon as it is
93 | possible to do so.
94 |
95 | # Usage
96 |
97 | Add the *shebang* as the first line in your script: `#!/usr/bin/swift sh`.
98 |
99 | Your dependencies are determined via your `import` lines:
100 |
101 | ```swift
102 | #!/usr/bin/swift sh
103 | import AppUpdater // @mxcl
104 | // ^^ https://github.com/mxcl/AppUpdater, latest version
105 |
106 | import PromiseKit // @mxcl ~> 6.5
107 | // ^^ mxcl/PromiseKit, version 6.5.0 or higher up to but not including 7.0.0 or higher
108 |
109 | import Chalk // @mxcl == 0.3.1
110 | // ^^ mxcl/Chalk, only version 0.3.1
111 |
112 | import LegibleError // @mxcl == b4de8c12
113 | // ^^ mxcl/LegibleError, the precise commit `b4de8c12`
114 |
115 | import Path // mxcl/Path.swift ~> 0.16
116 | // ^^ for when the module-name and repo-name are not identical
117 |
118 | import BumbleButt // https://example.com/bb.git ~> 9
119 | // ^^ non-GitHub URLs are fine
120 |
121 | import CommonTaDa // git@github.com:mxcl/tada.git ~> 1
122 | // ^^ ssh URLs are fine
123 |
124 | import TaDa // ssh://git@github.com:mxcl/tada.git ~> 1
125 | // ^^ this style of ssh URL is also fine
126 |
127 | import Foo // ./my/project
128 | import Bar // ../my/other/project
129 | import Baz // ~/my/other/other/project
130 | import Fuz // /I/have/many/projects
131 | // ^^ local dependencies must expose library products in their `Package.swift`
132 | // careful: `foo/bar` will be treated as a GitHub dependency; prefix with `./`
133 | // local dependencies do *not* need to be versioned
134 |
135 |
136 | import Floibles // @mxcl ~> 1.0.0-alpha.1
137 | import Bloibles // @mxcl == 1.0.0-alpha.1
138 | // ^^ alphas/betas will only be fetched if you specify them explicitly like so
139 | // this is per Semantic Versioning guidelines
140 | ```
141 |
142 | `swift-sh` reads the comments after your imports and fetches the requested
143 | SwiftPM dependencies.
144 |
145 | It is not necessary to add a comment specification for transitive dependencies.
146 |
147 | # Editing in Xcode
148 |
149 | The following will generate an Xcode project (not in the working directory, we
150 | keep it out the way in our cache directory) and open it, edits are saved to your
151 | script file.
152 |
153 | ```
154 | $ swift sh edit ./myScript
155 | ```
156 |
157 | # Examples
158 |
159 | * [Tweet deleter](https://gist.github.com/mxcl/002c3514d50b73287c89268c45662394)
160 | * [PostgreSQL Check](https://gist.github.com/joscdk/c4b89add26509c6dfabf84974e62543d)
161 |
162 | # Converting your script to a package
163 |
164 | Simple scripts can quickly become bigger projects that would benefit from being
165 | packages that you build with SwiftPM. To help you migrate your project we
166 | provide `swift sh eject`, for example:
167 |
168 | $ swift sh eject foo.swift
169 |
170 | creates a Swift package in `./Foo`, from now on use `swift build` in the
171 | `Foo` directory. Your script is now `./Foo/Sources/main.swift`.
172 |
173 | # Use in CI
174 |
175 | If you want to make scripts available to people using CI; use `stdin`:
176 |
177 | brew install mxcl/made/swift-sh
178 | swift sh <(curl http://example.com/yourscript) arg1 arg2
179 |
180 | # Internal Details
181 |
182 | `swift sh` creates a Swift `Package.swift` package manager project with
183 | dependencies in a directory below the swift-sh cache directory †,
184 | builds the executable, and then executes it via `swift run`.
185 | The script is (only) rebuilt when the script file is newer than the executable.
186 |
187 | † Specify the cache parent directory using the (FreeDesktop) environment
188 | variable XDG_CACHE_HOME. If unspecified, on macOS `swif-sh` uses
189 | `$HOME/Library/Developer/swift-sh.cache`, and otherwise it uses
190 | `$HOME/.cache/swift-sh`.
191 |
192 | # Swift Versions
193 |
194 | `swfit-sh` v2 requires Swift 5.1. We had to drop support for Swift v4.2
195 | because maintenance was just too tricky.
196 |
197 | `swift-sh` uses the active tools version, (ie: `xcode-select`) or whichever
198 | Swift is first in the `PATH` on Linux. It writes a manifest for the package
199 | it will `swift build` with that tools-version. Thus Xcode 11.0 builds with Swift 5.1.
200 | Dependencies build with the Swift versions they declare support for, provided
201 | the active toolchain can do that (eg. Xcode 11.0 supports Swift 4.2 and above)
202 |
203 | To declare a support for specific Swift versions in your script itself, use
204 | `#if swift` or `#if compiler` directives.
205 |
206 | # Alternatives
207 |
208 | * [Beak](https://github.com/yonaskolb/Beak)
209 | * [Marathon](https://github.com/JohnSundell/Marathon)
210 |
211 | ---
212 |
213 | # Troubleshooting
214 |
215 | ### `error: unable to invoke subcommand: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-sh`
216 |
217 | If you got here via Google, you have a script that uses this tool, if you now
218 | install `swift-sh`, you will be able to run your script:
219 |
220 | brew install mxcl/made/swift-sh
221 |
222 | Or see the [above installation instructions](#Installation).
223 |
224 | [badge-platforms]: https://img.shields.io/badge/platforms-macOS%20%7C%20Linux-lightgrey.svg
225 | [badge-languages]: https://img.shields.io/badge/swift-5.1%20%7C%205.2%20%7C%205.3%20%7C%205.4%20%7C%205.5%20%7C%205.6%20%7C%205.7%20%7C%205.8%20%7C%205.9%20%7C%206.0-orange.svg
226 |
--------------------------------------------------------------------------------
/Sources/Command/CommandLine.usage.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Path
3 |
4 | //MARK: CommandLine.usage
5 |
6 | public extension CommandLine {
7 | static var usage: String {
8 | var rv = """
9 | swift sh