# swift -e runs code directly from the command line

In this blog post, I explain `swift -e` which is a new command-line option introduced in Swift 5.8 / Xcode 14.3 Beta 1, that allows Swift one-liners.

A Swift **one-liner** is a line of code written in the Swift programming language that can be **executed directly from the command line** without creating a separate file.

It is a convenient and efficient way to perform small, one-off tasks or manipulate data.

# Motivation

Previously you had to invoke `swift` from the command line by passing it the filename of a script to run:

```bash
swift aProgram.swift
```

If you wanted to pass the code on the command line, you had to do it awkwardly through Standard Input (stdin)

```bash
echo 'print("good")' | swift -
```

[Ruby](https://hashrocket.com/blog/posts/ruby-on-the-command-line) and [Perl](https://www.perl.com/pub/2004/08/09/commandline.html/) provide a nicer way and that's why `swift -e` was introduced.

# Explained: `swift -e`

In 5.8 the `swift` command has an option `-e` to execute a line of code provided on the command line rather than passed through stdin or a source file.

%[https://github.com/apple/swift/issues/48430] 

## Execute a one-liner

The code itself needs to be between single quotation marks.

```bash
swift -e 'print("better")'
```

## Multiple arguments

Multiple `-e` arguments can be provided.

```bash
swift -e 'let x = "best"' -e 'print(x)'
```

> The values of the “-e” switches are each treated as one line of source code, which are concatenated together into a temporary main.swift file and passed to the frontend jobs.

Multiple statements might not be avoidable, especially when using APIs from `Foundation` for which you need an import statement.

```bash
swift -e 'import Foundation' -e 'print(FileManager.default.currentDirectoryPath)'
```

## Multiple statements with a single `e` argument

I found it easier to separate multiple statements with `;`

```bash
swift -e 'let x = "best of the best" ; print(x)'
```

## Read standard input in your one-liner

If your Swift one-liner shall process data passed through stdin then you can use the Standard Library function [`readLine`](https://developer.apple.com/documentation/swift/readline(strippingnewline:))

```bash
echo "outsideInput" | swift -e 'readLine() == "outsideInput" ? print("pass") : print("fail")'
```

## Pass textual data to the standard output

Using the Standard Library function [`print`](https://developer.apple.com/documentation/swift/print(_:separator:terminator:)) will allow other scripts to consume the information assuming the caller uses pipes to chain commands.

```bash
 echo "outsideInput" | swift -e 'readLine() == "outsideInput" ? print("pass") : print("fail")' | xargs echo
```

The output is the same as in the previous example but I am sure you get my point.

## Example: commenting out all code in a Swift file

Here is a more real-life example in which we use standard commands as well as our Swift one-liner to comment out all code in a Swift file.

```bash
cat someFile.swift | swift -e 'while let line = readLine() { print("//" + line) }' | tee someFile.swift
```

1. `cat` will read the file content of `someFile.swift` and we pipe (`|`) the file content into our Swift one-liner
    
2. The Swift one-liner will iterate over the received lines in standard input and writes each line, appending two forward slashes, to standard output
    
3. `tee` reads from the standard input and writes to both standard output (terminal) and into `someFile` at the same time. Hence the file content gets replaced and we can see the commented-out source code in the terminal.
    

There might be a more elegant way to do all this but I am not an expert on all the command-line tools on Mac/Linux. So I appreciate that I can combine my little bash/terminal skills and complement them with my Swift knowledge.

# Summary

A nifty `e`dition that hopefully expands the use of Swift for scripting.

I am curious if further options/switches will be introduced to match the behavior to ruby, e.g. `-n` and `-p` switches as explained [here](https://robm.me.uk/2013/11/ruby-enp/).
