LoginSignup
7
5

More than 3 years have passed since last update.

Swiftでちょっとしたスクリプトを書く

Last updated at Posted at 2020-01-24

SwiftというとiOS開発(あるいはiPad/Macアプリ)でしか使いませんが、コマンドラインからの実行もできます。
(当たり前っちゃ当たり前ですが)
Swiftをシェルスクリプトみたいに使えないかな? とふと思って、調べてみたら普通に色々できたので、書いてみます。

実行

「script.swift」というSwiftファイルを動かしたいとしたら、下記で実行できます。

$ swift script.swift

コマンドライン引数も指定できます。

$ swift script.swift arg1 arg2 ...

できること

  • 標準入出力
  • ファイル操作
  • WebのAPIを叩く

スクリプトでやらせたいことはだいたいできる気がします。
慣れ親しんだSwiftでツール作成もできるとなれば嬉しいですね。

AtCoderやる人だったら、Playgroundだと標準入力受け取れないので、
コマンドラインで実行すると捗ると思います。

コマンドライン引数の受け取り方

let arg1 =  CommandLine.arguments[1]

標準入力

let input = readLine() //これでコマンドライン上では入力待ち状態になります

標準出力

print()です。

APIを叩く

自分では試してませんが、下記でできるとのこと。

Swiftをシェルスクリプトのように使う一番簡単な方法

各種ディレクトリパスの取得

FileManagerを使います。
なおFoundationのクラスなので、import必須です。

let filemanager = FileManager.default

print(filemanager.homeDirectoryForCurrentUser)
print(filemanager.temporaryDirectory)
print(filemanager.currentDirectoryPath)

ファイル読み込み

//ファイル名をコマンドライン引数の1番目でもらっている前提
let fileName = "./" + CommandLine.arguments[1]
if let text = try? String(contentsOfFile: fileName, encoding: String.Encoding.utf8) {
    print(text)
}

ファイル書き込み

do {
    try text?.write(toFile: "./hoge.txt", atomically: true, encoding: String.Encoding.utf8)
} catch let message {
    print("error!")
    print(message)
}

スクリプトが動いているディレクトリ直下にhoge.txtというファイルが作られます。

サンプルツール

やり方を紹介するだけだとつまらないので、スクリプトを書いてみました。

$ swift script.swift input.txt output.txt

こんな感じで実行してやると、インプットファイルの「。」の位置で改行してくれます。
つまり、

input.txt
 二人の若い紳士しんしがすっかりイギリスの兵隊のかたちをしてぴかぴかする鉄砲てっぽうをかついで白熊しろくまのような犬を二疋ひきつれてだいぶ山奥やまおくの木の葉のかさかさしたとこをこんなことを云いいながらあるいておりました。「ぜんたいここらの山は怪けしからんね鳥も獣けものも一疋も居やがらんなんでも構わないから早くタンタアーンとやって見たいもんだなあ。」「鹿しかの黄いろな横っ腹なんぞに二三発お見舞みまいもうしたらずいぶん痛快だろうねえくるくるまわってそれからどたっと倒たおれるだろうねえ。」

これが、

output.txt
 二人の若い紳士しんしがすっかりイギリスの兵隊のかたちをしてぴかぴかする鉄砲てっぽうをかついで白熊しろくまのような犬を二疋ひきつれてだいぶ山奥やまおくの木の葉のかさかさしたとこをこんなことを云いいながらあるいておりました
ぜんたいここらの山は怪けしからんね
鳥も獣けものも一疋も居やがらん
なんでも構わないから早くタンタアーンとやって見たいもんだなあ
」「鹿しかの黄いろな横っ腹なんぞに二三発お見舞みまいもうしたらずいぶん痛快だろうねえ
くるくるまわってそれからどたっと倒たおれるだろうねえ

こうなります。
ツールの仕様上、インプットの末尾に「。」が来た場合、出力されません。

script.swift
import Foundation

let filemanager = FileManager.default
let currentPath = filemanager.currentDirectoryPath
var text = ""

func check() {
    guard CommandLine.arguments.count == 3 else {
        print("""
        This tool make a new file separated the words on different lines each Japanese period(。).
        This tool need two arguments.
        (example:) > swift script.swift input.txt output.txt
         argument 0: script file name
         argument 1:  input file name
         argument 2: output file name
        """)
        exit(0) //アプリ開発だと使っちゃダメ
    }
}

func input() {
    let fileName = currentPath + "/" + CommandLine.arguments[1]
    let inputFile = try? String(contentsOfFile: fileName, encoding: String.Encoding.utf8)
    guard let t = inputFile else {
        print("input file is not found!!!")
        return
    }
    text = t
}

func output() {
    text = text.split(whereSeparator: { $0 == "。" }).joined(separator: "。\n")
    //フルパスでなくても、1) ./hoge.txt 2) hoge.txt でもカレントディレクトリ直下にファイルが作成される
    let ouputFileName = currentPath + "/" + CommandLine.arguments[2]
    do {
        try text.write(toFile: ouputFileName, atomically: true, encoding: String.Encoding.utf8)
    } catch let e {
        print("write file failed!!!")
        print(e)
    }
}

check()
input()
output()

このサンプルは著作権フリーなので、お好きに改変してお使いください。

試行錯誤のメモ

  • 最初句点の置換をreplaceSubrange(_:with:)でやろうとしたら、最初にヒットした文字しかできなくて断念
  • 更にString → [Character] → map使って"。"と一致したら"。\n"としたらCharacterに二文字は入れられません、でエラー(そりゃそうだ)

書いてから気づいたこと

上記のサンプルツール書くとき、新しいSwiftファイルとして作成して、
開発ディレクトリを直で編集していたんですが、これでやると入力補完が十分効かなくなって辛かったです。
ちょっと大袈裟にはなりますが、Command Line ToolとしてProjectつくってやるとキー補完も効くし、git管理もできるし、ビルドもできるんで便利ですね。
コマンドライン引数は流石に無理やろ……? と思ったら、それもイケるみたいです。すごいぞXcode。

XcodeでCommand Line Tool実行時にコマンドライン引数を渡す

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5