【问题标题】:Allow program to read from stdin or arguments in Swift允许程序从 Swift 中的标准输入或参数读取
【发布时间】:2019-11-26 22:14:29
【问题描述】:

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

  • 接受来自标准输入的单个参数或管道数据,并打印出来
  • 如果两者都缺失,则打印使用消息。

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

  1. swift main.swift 应该输出“请提供一些输入”
  2. swift main.swift argument 应该输出“argument”
  3. echo | swift main.swift 应该输出“请提供一些输入”
  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() 导致执行暂停,等待输入。如果您在没有输入的情况下按回车,则会返回正确的消息,但我想避免手动输入空行的必要性。

如何从标准输入读取启用读取,同时在标准输入为空白且没有参数时不会导致暂停?

【问题讨论】:

    标签: swift command-line-arguments stdin


    【解决方案1】:

    我认为问题在于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)")
    

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

    【讨论】:

    • 我添加了我的最终解决方案以供参考,但使用标志是缺失的部分。
    【解决方案2】:

    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)
    

    【讨论】:

      猜你喜欢
      • 2011-08-06
      • 2014-11-17
      • 1970-01-01
      • 2014-08-02
      • 1970-01-01
      • 2016-04-19
      • 2011-03-30
      • 2012-10-31
      • 1970-01-01
      相关资源
      最近更新 更多