python 实现命令行工具 tee

最近,朋友 Litreily 发表了文章Linux指令 - tee的实现 ,是用 C 语言实现的 tee 命令,那我凑个热闹用 python 实现一下下!

20181025154039778364827.png

tee命令

macOS下也有 tee 命令,好像跟 linux 下的有一点点差别,这个小节讲一下 macOS 下的 tee 命令的使用,总该感受下它的功能才能实现它吧!

tee的功能

打开终端,输入命令 man tee 可以查看 tee 的手册,介绍非常简单,当然是因为这个命令功能很简单。

TEE(1)                    BSD General Commands Manual                   TEE(1)

NAME
     tee -- pipe fitting

SYNOPSIS
     tee [-ai] [file ...]

DESCRIPTION
     The tee utility copies standard input to standard output, making a copy in zero or more files.  The output is unbuffered.

     The following options are available:

     -a      Append the output to the files rather than overwriting them.

     -i      Ignore the SIGINT signal.

     The following operands are available:

     file  A pathname of an output file.

     The tee utility takes the default action for all signals, except in the event of the -i option.

     The tee utility exits 0 on success, and >0 if an error occurs.

STANDARDS
     The tee function is expected to be POSIX IEEE Std 1003.2 (``POSIX.2'') compatible.

BSD                              June 6, 1993                              BSD

功能简单来说就是把标准输入传输给标准输出(打印出来)的同时将输入内容写入到指定文件,而在指定文件的时候加上 -a 会在文件内容的基础上追加输入而不是覆盖^[tee 命令]。

tee的使用

还是得实际使用使用才能感受它的功能:

$ tee log.txt
test
test
原来如此
原来如此
^C
$ cat log.txt
test
原来如此
$ tee -a log.txt
生活如此多彩
生活如此多彩
^C
$ cat log.txt
test
原来如此
生活如此多彩
$ tee
hah
hah
^C
  1. tee 命令指定文件 log.txt,输入内容敲回车就会打印输入的内容,比如 test原来如此,CTRL + c 退出命令,用 cat 命令查看 log.txt 的内容与输入的内容一致。
  2. 加入 -a 选项,就会在指定文件追加输入的内容,比如 生活如此精彩
  3. 不指定文件的话,只会打印输入的内容。

python实现tee

这里只实现上面 tee的使用 小节中测试的功能。

文件准备

  1. 新建文件:touch tee

  2. 为文件添加运行权限: chmod +x tee

  3. 文件中指明解释器,添加以下内容到 tee 文件中:

    #!/usr/bin/env python3
    
  4. 文件中导入必要的库:

    import sys
    import argparse
    
    • sys 库用于操作标准输入输出;
    • argparse 库用于解析命令参数,这个库的基本使用可以参考我的另一篇文章 argparse 库的使用

解析命令参数

这里将使用 argparse 库解析参数的操作封装为函数 getargs:

def getargs():
    """获取命令参数
    """
    parser = argparse.ArgumentParser(description="The tee utility copies standard \
                                                input to standard output, making a \
                                                copy in zero or more files.  The \
                                                output is unbuffered.")
    parser.add_argument('-v', '--version', action='version', version="v 1.0.0")
    parser.add_argument('-a', '--append', action="store_true", default=False, help='Append the output to the files rather than overwriting them.')
    parser.add_argument('file', nargs='*', help='A pathname of an output file.')
    return parser.parse_args()

tee功能实现

直接在 __main__ 中实现 tee 的功能如下:

if __name__ == '__main__':
    args = getargs()
    filemode = 'a' if args.append else 'w'
    while True:
        line = sys.stdin.readline()
        sys.stdout.write(line)
        for file in args.file:
            with open(file, filemode) as f:
                f.write(line)
        if filemode is 'w':
            filemode = 'a'

可以看到代码非常简单就实现了 tee 的完整功能,直接操作 sys.stdinsys.stdout^[使用python实现tee的效果] 和 文件^[实现tee命令]即可!最终代码可参考:tools-with-script/tee/tee

测试

$ ./tee --help
usage: tee [-h] [-v] [-a] [file [file ...]]

The tee utility copies standard input to standard output, making a copy in
zero or more files. The output is unbuffered.

positional arguments:
  file           A pathname of an output file.

optional arguments:
  -h, --help     show this help message and exit
  -v, --version  show program's version number and exit
  -a, --append   Append the output to the files rather than overwriting them.
$ ./tee
12
12
$ ./tee log.txt
where
where
who i am
who i am
$ cat log.txt
where
who i am
$ ./tee -a log.txt
that's good
that's good
$ cat log.txt
where
who i am
that's good
$ ./tee -a log.txt log1.txt
Wonderful
Wonderful
$ cat log.txt
where
who i am
that's good
Wonderful
$ cat log1.txt
Wonderful

测试步骤解释如下:

  1. 打印帮助信息;
  2. 不指定任何参数,只会将标准输入打印到标准输出;
  3. 指定文件 log.txt,标准输入分别输入 wherewho i am,标准输出也分别打印了;
  4. 查看 log.txt 内容与上一步的标准输入一致;
  5. 指定文件 log.txt并指定为追加模式,标准输入 that's good ,标准输出正常显示 that's good
  6. 查看 log.txt 内容是在原来的内容上追加了上一步输入的 that's good
  7. 指定两个文件 log.txtlog1.txt,并指定为追加模式,标准输入 Wonderful,标准输出正常打印;
  8. 查看 log.txt 内容是在原来的内容上追加了上一步输入的 that's good,而新文件 log1.txt 内容为上一步的 Wonderful