程序应该只关注一个目标,并尽可能把它做好。让程序能够互相协同工作。应该让程序处理文本数据流,因为这是一个通用的接口 –Malcolm Douglas McIlroy(Unix管道发明者)

此前写过这篇:正则表达式一例

我试着用多种语言去完成这个任务,当我试着用bash和perl去解决这个问题的时候,发现perl和命令行的的结合十分紧密,很容易将perl作为管道的一截,就像sed或是grep一样。

而管道是我极喜欢的Unix特性之一。

一旦习惯了管道,将程序作为过滤器,就十分容易与Unix工具箱中的其他组件协作,如此一来绝大多数的工作都省了!过滤器之间协作的力量常常十分惊人。

##Pipeline 管道(Pipeline)依赖于这样的约定,每个程序一开始有两个I/O数据流可用:标准输入和标准输出,许多程序都可以写作过滤器,从标准输入顺序读入数据,并且向标准输出写数据。

###语法 典型语法是使用ASCII中的垂直线|

###demo ls -l | less

ls用于在Unix下列出目录内容,less是一个有搜索功能的交互式的文本分页器

###从管道中获益 上边的less将程序员从为自己的软件开发分页器的负担中解放了出来:他们只需要把他们的输出用过“管道”导入到less程序中即可,可以完全不顾分页问题

这样就避免了代码的臃肿,降低和全局复杂度

《代码大全》中给出过一个观点:
>软件工程的本质即是管理复杂度

管道触进了“Do one thing, Do it well”,于是当然也有利于“Keep it Simple Stupid”

而这些对于一个复杂项目的成败都是至关重要的

###other demo tr -c '[:alnux]' '[\n*]' | sort -iu |grep -v '^[0-9]*$'

以上操作把标准输入的文本生成了经过排序的单词表送到标准输出

  • 第一个命令把标准输入中非字母和数字的字符在标准输出中转化为新行。
  • 第二个命令对标准输入的行进行排序,对于重复的相邻行只保留一个,然后把排好序的数据写到标准输出。
  • 第三个命令去掉所有只包含数字的行。

##Pipeline and Python

那么Python程序能否方便地作为过滤器放到管道里呢。毕竟我不想捏着鼻子写perl。

github了一下,找到这个pythonpy

下边我们试着用pythonpy来完成正则表达式一例中的任务

###环境 * zsh * virtualenv(python3) ps:涉及到中文的问题尽量用python3 * pip install pythonpy

###代码

1
2
3
4
5
filenames=(ls /PATH/*.txt)
for file in $filenames
do
cat $file | py -x "re.sub(r'[\u4e00-\u9fa5].*','',x)">output_$file
done

怎么样,够简洁吧!

###pythonpy demo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#计算
py '3 * 1.5' #4.5

#py -x :treat each row of stdin as x
py 'range(3)' | py -x 'int(x)*7' #0\n7\n14
echo 'a1,b1,c1\na2,b2,c2' | py -x 'x.split(",")[1]' #b1\nb2
##Append ".txt" to each line of input
py 'range(3)' | py -x 'x + ".txt"' #0.txt\n1.txt\n2.txt
##Append ".txt" to every file in the directory,ps:还是使用ipython或是shell的for来做吧
ls | py -x '"mv `%s` `%s.txt`" % (x,x)' | sh 

#py -l :treat list of stdin as l
py 'range(3)' | py -l 'sum(int(x) for x in l)'

#Count words beginning with each letter 。多熟悉collections(python cookbook),集合的特性相关
cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'collections.Counter(l).most_common(5)'

###python脚本作为过滤器 如果我们想将python脚本当做过滤器用在管道里,关键便是让它能处理输入(stdin)输出(stdout)流

1
2
3
4
#myscript.py
import sys
for line in sys.stdin:
  sys.stdout.write(line) #sys.stdout.write与print的区别是,print会默认添加换行符

使用:cat text.txt|python myscript.py

#参考 * pythonpy * 管道_Unix wiki * Unix编程艺术