允许程序从 Swift 中的标准输入或参数读取

Allow program to read from stdin or arguments in Swift

我正在尝试编写一个 Swift 程序

假设代码包含在main.swift中,我们有四种情况:

  1. swift main.swift 应该输出 "Please provide some input"
  2. swift main.swift argument 应该输出 "argument"
  3. echo | swift main.swift 应该输出 "Please provide some input"
  4. echo argument | swift main.swift 应该输出 "argument"

对于复合词 echo argument1 | swift main.swift argument2argument2 优先。

满足 1-3 很简单:

import Foundation

var input: String? = nil

if CommandLine.arguments.count > 1 {
    input = CommandLine.arguments[1]
}

guard let input = input else {
    print("Please provide some input")
    exit(0)
}

print(input)

但是,echo argument | swift main.swift 显然会打印用法消息,因为没有参数。添加一些代码,

import Foundation

var input: String? = nil

if CommandLine.arguments.count > 1 {
    input = CommandLine.arguments[1]
} else {
    while let line = readLine() {
        if input == nil {
            if line.isEmpty { break }
            input = line
        } else {
            input! += "\n" + line
        }
    }
}

guard let input = input else {
    print("Please provide some input")
    exit(0)
}

print(input)

现在情况 2-4 按预期工作,但情况 1 有问题。 readLine() 导致执行暂停,等待输入。如果你在没有输入的情况下按 return,正确的消息是 returned,但我想避免手动输入空白行的必要性。

如何从 stdin 读取启用读取,同时在 stdin 为空且没有参数时不会引起暂停?

我认为问题在于 readLine() 将只是等待某种输入,即使它只是使用 ctrl-d 向其发送行尾。对于您的使用,是否可以添加一个参数来告诉程序它应该等待输入?否则,它可以假设它不应该等待任何事情?

例如:

import Foundation

func readInput () -> String? {
    var input:String?

    while let line = readLine() {
        if input == nil {
            if line.isEmpty { break }
            input = line
        } else {
            input! += "\n" + line
        }
    }

    return input
}

var input: String? = nil

if CommandLine.arguments.count > 1 {
    input = CommandLine.arguments[1]

    if (input == "-i") {
        input = readInput()
    }
}

guard let input = input else {
    print("Please provide some input")
    exit(0)
}

print("input: \(input)")

然后你最终得到这样的用法和输出:

Josh Buhler 提供了缺失的部分 — 传递一个标志以启用读取标准输入。这是我最终的、简化的完整性解决方案。

import Foundation

guard CommandLine.arguments.count > 1 else {
    print("Please provide an argument, or pass - to read stdin")
    exit(0)
}

var input = CommandLine.arguments[1]

if input == "-" {
    input = AnyIterator { readLine() }.joined(separator: "\n")
}

// do something with input
print(input)