Go command parameters

 

os 包提供一些函数和变量,以平台无关的方式和操作系统交互,命令行参数以 os 包中 Args 名字的变量提供程序访问, 在 os 包之外,使用 os.Args 这个名字。

变量 os.Args 是一个字符串切片(slice)。可以通过 s[i] 来访问单个元素,通过 s[m:n] 来访问一段连续子区间,长度用 len(s) 来获取。

Go 语言中,所有的索引都使用半开区间,即包含第一个元素,不包含最后一个元素。

例如: slice s[m:n] 其中 0 <= m <= n <= len(s),包含 m - n 个元素。

os.Args[0] 是命令本身的名字; 其余的元素是程序开始执行时的参数。

实现一个 echo 命令

// gop1.io/ch1/echo1
// echo1 输出其命令行参数
package main

import (
 "fmt"
 "os"
 "strings"
)

func main() {
 echo3()
}

func echo1() {
 var s, sep string
 for i := 1; i < len(os.Args); i++ {
  s += sep + os.Args[i]
  sep = " "
 }
 fmt.Println(s)
}

func echo2() {
 s, sep := "", ""
 for _, arg := range os.Args[1:] {
  s += sep + arg
  sep = " "
 }
 fmt.Println(s)
}

func echo3() {
 fmt.Println(strings.Join(os.Args[1:], " "))
}

找出重复行

用于文件复制、打印、检索、排序、统计的程序,通常有一个相似的结构:在输入接口上循环读取,软后对每一个元素进行一些计算,在运行时或者结束时输出结果。

package main

import (
 "bufio"
 "fmt"
 "os"
)

func main() {
 // 内置函数 make 创建 map
 counts := make(map[string]int)
 input := bufio.NewScanner(os.Stdin)
 for input.Scan() {
  counts[input.Text()]++
 }
 // 注意: 忽略 input。Err() 中可能的错误
 for line, n := range counts {
  if n > 1 {
   fmt.Printf("%d\t%s\n", n, line)
  }
 }
}

bufio 包可以简便和搞笑(高效)地处理输入和输出。

其中一个最有用的特性时被称为扫描器的类型(Scanner),它可以读取输入,以行或者单词为单位断开,这是处理以行为单位的输入内容的最简单方式。

input := bufio.NewScanner(os.Stdin)

Scanner 从程序的标准输入进行读取。每次调用 input.Scan() 读取下一行,并且将结尾的换行符去掉;

通过调用 input.Text() 来获取读到的内容。

Scan() 函数在读到新行时返回 true,在没有更多内容的时候返回 false

package main

import (
 "bufio"
 "fmt"
 "os"
)

func main() {
 dup2()
}

func dup2() {
 counts := make(map[string]int)
 files := os.Args[1:]
 if len(files) == 0 {
  countLines(os.Stdin, counts)
 } else {
  for _, arg := range files {
   f, err := os.Open(arg)
   if err != nil {
        // %v 可以使用默认格式显示任意类型的值;
    fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
    continue
   }
   countLines(f, counts)
   f.Close()
  }
 }
 for line, n := range counts {
  if n > 1 {
   fmt.Printf("%d\t%s\n", n, line)
  }
 }
}

func countLines(f *os.File, counts map[string]int) {
 input := bufio.NewScanner(f)
 for input.Scan() {
  counts[input.Text()]++
 }
}

函数 os.Open 返回两个值,第一个时打开的文件 (*os.File),该文件随后被 Scanner 读取。第二个返回值时一个内置的 error 类型的值。如果 err 等于 nil ,标准文件成功打开。文件在被读到结尾的时候,Close() 函数关闭文件释放资源。

map 时一个使用 make 创建的数据结构的引用。当一个 map 被传递给一个函数时,函数接收到这个引用的副本,所以被调用函数中对于 map 数据结构中的改变对函数调用者使用的 map 引用也是可见的。

package main

import (
 "fmt"
 "io/ioutil"
 "os"
 "strings"
)

func dup3() {

 counts := make(map[string]int)
 for _, filename := range os.Args[1:] {
  data, err := ioutil.ReadFile(filename)
  if err != nil {
   fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
   continue
  }
  for _, line := range strings.Split(string(data), "\n") {
   counts[line]++
  }
 }
 for line, n := range counts {
  if n > 1 {
   fmt.Printf("%d\t%s\n", n, line)
  }
 }
}

func main() {
 dup3()
}

ReadFile 函数(io/ioutil)读取整个文件的内容,返回一个可以转化成字符串的字节 Slicestring.Split 函数将一个字符串分割为一个由字符串组成的 Slice。


If you like TeXt, don’t forget to give me a star. :star2:

Star This Project