Giter Site home page Giter Site logo

swiftshell's Introduction

Platform Language Carthage compatible License

For Swift 2.2+. See this branch for Swift 3.

Not currently available for Linux, because NSTask and NSFileHandle have not been fully ported yet.

SwiftShell

An OS X Framework for command-line scripting in Swift.

See also

Example

Print line numbers

import SwiftShell

do {
	// If there is an argument, try opening it as a file. Otherwise use standard input.
	let input = try main.arguments.first.map {try open($0)} ?? main.stdin

	input.lines()
		.enumerate().forEach { (linenr,line) in print(linenr+1, ":", line) }

	// Add a newline at the end
	print("")
} catch {
	exit(error)
}

Launched with e.g. cat long.txt | print_linenumbers.swift or print_linenumbers.swift long.txt this will print the line number at the beginning of each line.

Run commands

Print output

try runAndPrint(bash: "cmd1 arg | cmd2 arg") 

Run a shell command just like you would in the terminal. The name may seem a bit cumbersome, but it explains exactly what it does. SwiftShell never prints anything without explicitly being told to.

In-line

let date: String = run("date", "-u")
print("Today's date in UTC is " + date)

Similar to $(cmd) in bash, this just returns the output from the command as a string, ignoring any errors.

Asynchronous

let command = runAsync("cmd", "-n", 245)
// do something with command.stderror or command.stdout
try command.finish()

Launch a command and continue before it's finished. You can process standard output and standard error, and optionally wait until it's finished and handle any errors.

If you read all of command.stderror or command.stdout it will automatically wait for the command to finish running. You can still call finish() to check for errors.

Parameters

The 3 run functions above take 2 different types of parameters:

(executable: String, _ args: Any ...)

If the path to the executable is without any /, SwiftShell will try to find the full path using the which shell command.

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.

run("echo", "We are", 4, "arguments")
// echo "We are" 4 arguments

let array = ["But", "we", "are"]
run("echo", array, array.count + 2, "arguments")
// echo But we are 5 arguments

(bash bashcommand: String)

These are the commands you normally use in the Terminal. You can use pipes and redirection and all that good stuff. Support for other shell interpreters can easily be added.

Errors

If the command provided to runAsync could not be launched for any reason the program will print the error to standard error and exit, as is usual in scripts (it is quite possible SwiftShell should be less usual here).

The runAsync("cmd").finish() method on the other hand throws an error if the exit code of the command is anything but 0:

let command = runAsync("cmd", "-n", 245)
// do something with command.stderror or command.stdout
do {
	try command.finish()
} catch ShellError.ReturnedErrorCode(let error) {
	// use error.command or error.errorcode
}

The runAndPrint command can also throw this error, in addition to this one if the command could not be launched:

} catch ShellError.InAccessibleExecutable(let path) {
	// ‘path’ is the full path to the executable
}

Instead of dealing with the values from these errors you can just print them:

} catch {
	print(error)
}

... or if they are sufficiently serious you can print them to standard error and exit:

} catch {
	exit(error)
}

 

When launched from the top level you don't need to catch any errors, but you still have to use try.

Output

main.stdout is for normal output and main.stderror for errors:

main.stdout.writeln("everything is fine")

main.stderror.write("something went wrong ...")

Input

Use main.stdin to read from standard input:

let input: String = main.stdin.read()

Main

So what else can main do? It is the only global value in SwiftShell and contains all the contextual information about the outside world:

var encoding: UInt
lazy var env: [String : String]

lazy var stdin: ReadableStream
lazy var stdout: WriteableStream
lazy var stderror: WriteableStream

var currentdirectory: String
lazy var tempdirectory: String

lazy var arguments: [String]
lazy var name: String

Everything is mutable, so you can set e.g. the text encoding or reroute standard error to a file.

Setup

Shell script

  • In the Terminal, go to where you want to download SwiftShell.

  • Run

      git clone https://github.com/kareman/SwiftShell.git
      cd SwiftShell
    
  • Copy/link Misc/swiftshell to your bin folder or anywhere in your PATH.

  • To install the framework itself, either:

    • run xcodebuild install from the project's root folder. This will install the SwiftShell framework in ~/Library/Frameworks.
    • or run xcodebuild and copy the resulting framework from the build folder to your library folder of choice. If that is not "~/Library/Frameworks" or "/Library/Frameworks" then make sure the folder is listed in $SWIFTSHELL_FRAMEWORK_PATH.

Then include this in the beginning of each script:

#!/usr/bin/env swiftshell

import SwiftShell

See the Swift 3 branch.

Add this to your Cartfile:

github "kareman/SwiftShell"

Then run carthage update and add the resulting framework to the "Embedded Binaries" section of the application. See Carthage's README for instructions.

Xcode command-line application

Sadly it is not possible to include a framework in an Xcode command-line application. But you can import one. Set the build settings FRAMEWORK_SEARCH_PATHS and LD_RUNPATH_SEARCH_PATHS to include a folder containing the SwiftShell framework. Or if you want the command line application to be self-contained you can include all the source files from SwiftShell in the command line target itself, and add "#import "NSTask+NSTask_Errors.h" to the bridging header.

License

Released under the MIT License (MIT), http://opensource.org/licenses/MIT

Some files are covered by other licences, see included works.

Kåre Morstøl, NotTooBad Software

swiftshell's People

Contributors

kareman avatar kenthinson avatar beltex avatar

Watchers

James Cloos avatar Ben DiFrancesco avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.