There are a lot of command line argument parsers written in Swift available on Github, so when I needed one for a client project I was surprised I could not find any which fulfilled these requirements:
- treat unrecognised arguments as an error and list them.
Nor could I find any where it would be relatively easy to add these features, since most just loop through the arguments from first to last and have one big function trying to find out what to do with each of them. That becomes messy quickly.
I think it’s much simpler to create multiple small argument parsers, where each one in turn takes in the list of arguments, removes the ones it wants to handle and passes the rest on to the next one. Any arguments left over are then unrecognised and can be handled accordingly. This way the end user does not need to worry about the order of the arguments. The developer however needs to be careful about the order of the parsers.
Sam Burnstone recently wrote about how to convert a simple shell script to Swift. Here’s the same shell script rewritten using SwiftShell and FileSmith.
I really don’t like using the ‘rm’ shell command – one misplaced character and you can do some serious damage. But when working in the Finder I don’t think twice about deleting files, because I know I can always get them back from the trash. So here is a Swift shell script which does exactly that – it moves files to the trash instead of deleting them permanently.
The syntax is very simple – all parameters refer to file system items which should be moved to the trash:
trash file.txt a_folder
trash *.m *.h
I’m rewriting Moderator (yet another command-line argument parser), and with Swift now being available for both OS X and Linux (Ubuntu) it should support a syntax which enables applications to fit in on both platforms.
POSIX* is I think the closest thing to a standard for this, so it will be the basis, with some modifications (The Python documentation also has some good insights).
* OS X is POSIX compliant and so is Linux (mostly).
To be honest I’m not very good at shell scripting. It’s very useful for automation so I would like to be, but I just don’t like the syntax. For instance, this is how you check if a variable is greater than 100:
if [ $var -gt 100 ]
<do some stuff>
And here’s how to check if the file referred to in the first argument is readable and not empty:
if [ -r $1 ] && [ -s $1 ]
So I would much rather use Swift, as the syntax is nice, very nice indeed. But the things that bash shell scripts actually are good at, like running shell commands and accessing the shell environment, are not that straightforward in Swift. Here’s how you can perform the various tasks using only the Swift Standard Library and Foundation: