Linux开发模式带给创业者的启示 - MacTalk 人生元编程

本文来自《MacTalk 人生元编程》的作者,池建强。原文戳这里。其实不好意思,第一次池建强讲的人生的道理就和编程一样(大概是这个意思)的时候,心里其实是有一些共鸣的,刚上大学的时候也有过类似的感觉,本来嘛,作为程序员习惯性地将事情代入编程也是常有的事。

这篇文章也有些共鸣和收获,于是转载下来,时时常拂拭,瞄上几眼,喵(●ↀωↀ●)✧

十五年前,我第一次在工作中使用 Linux 的时候,并不知道这个操作系统会对我的生活和职业产生多么大的影响。十五年后,我在「Linus,一生只为寻找欢笑」一文中写到:

当大家使用 Google 搜索时,使用 Kindle 阅读时,使用淘宝购物时,使用 QQ 聊天时,很多人并不知道,支撑这些软件和服务的,是后台成千上万台 Linux 服务器,它们时时刻刻都在进行着忙碌的运算和数据处理,确保数据信息在人、软件和硬件之间安全的流淌。

Linux 不仅仅从技术层面影响人们的生活,其本身就产生了很多有意思的话题和文化,我读了不少 Unix/Linux 相关的书籍,很多技术内容已经忘得一干二尽,但那些话题、模式和文化,却像醇香的好酒、美丽的传说,历久弥新,不断的为我带来思考和启发……

1、最初的想法,并不是决定性的

Linux 并不是凭空创造出来的,当年林纳斯(Linus)只是觉得迷你版 Unix 操作系统 Minix 的终端太难用了,既不能登录学校里的 Unix Server,也没法上网。这种功能缺陷对林纳斯这样的极客来说是无法接受的,于是他决定从硬件层面开始,重新为 Minix 设计一个终端仿真器。

当时是三月,也可能是四月,就算彼得盖坦街上的白雪已经化成了雪泥我也不知道,当然我也并不关心。大部分时间我都穿着睡衣趴在相貌平平的计算机前面噼噼啪啪的敲打键盘,窗户上的窗帘遮得严严实实,把阳光和外部世界与我隔离开来。 经过不眠不休的编程之后,终端仿真器做出来了,但那个时候林纳斯已经意识到自己的雄心壮志远不止于此,神山上的另一座圣杯「操作系统」已经向他发出了召唤,于是始有 Linux。

另一个伟大的操作系统 Macintosh,同样起步于一个微小的项目,期间历经换帅、更名、争吵、妥协,最终与 NextStep 经过长达四年的整合才形成现代的经典操作系统 OS X(参见《MacTalk·人生元编程》)。

几乎所有成功的产品都是边走边看做出来的。伟大的梦想,常常始于微不足道。

所以,很多人问我如何找到一份长期稳定的工作时,如何开启一个能够带来巨大成功的项目时,我只能说,最初的想法,并不是一切,开始去做就好了。

2、好的软件产品,常常源于开发者自身的需求

林纳斯为给自己开发终端仿真器最终做出了让其名垂青史的 Linux 操作系统,沃兹因为热爱计算机设计出了 Apple I,乔布斯想把1000首歌装进口袋推出了 iPod。

如果有什么工作能让你保持长久的热情,那一定是做自己需要的产品。当年我们在给程序员开发工具平台的时候,我要求每个工具研发人员都使用我们自己开发出来的工具,而不是仅仅把工具推给测试人员和项目组的程序员。过了一段时间,我发现那个 IDE 突然增加了很多「善解人意」并「出人意料」的功能。

如果有一天放下现在的工作,我一定会找一件足以让我穷尽半生去探索和追求的事情,用「术」解决问题,用「道」创造解决问题的方法,顺便改变生活。

3、优秀的程序员知道如何编程,卓越的程序员知道合理复用

林纳斯并没有尝试从零开始编写 Linux,而是以重用 Minix 的代码和理念作为开始,虽然在 Linux 最终的版本中几乎所有 Minix 代码都被移除或重写了,但它在 Linux 成长初期确实起到了类似脚手架的作用。

卓越的程序员通常都很懒,我们把这种懒叫做「建设性懒惰」,因为他们知道,很多时候我们要的都是最终的结果,而不是勤奋的过程。如果有可以复用的基础,显然比从零开始更具有建设性。

在开源社区澎湃发展的今天,我们有了更多的技术选择。所以,当你拿到一个轮子的需求时,去社区里找找问问,如果有可以复用的东西,就不要再费劲去造一个新轮子,况且你无法保证自己造的轮子比旧轮子好用。

我从来不是卓越的程序员,我只是模仿他们。

4、如果你有正确的态度,有趣的事情自然会找到你

林纳斯从写下第一行 Linux 代码的开始,就保持了一个开放的态度,可以说,Linux 一诞生就被打上了开源的烙印,这一点对其后续的发展起到了至关重要的作用。因为开放和开源,Linux 吸引了全球的开源爱好者和顶级黑客,无数卓越的程序员为 Linux 贡献了源代码,同时,林纳斯在开源协作方面也展现出了编程之外的天赋,他井井有条的运作着庞大的开源社区,回复邮件,发起讨论,阅读代码,合并分支,Linux 操作系统在开源社区的推动和林纳斯的调教下以惊人的速度发展。

从来没有一款如此复杂的软件系统是以这种松散的方式构建的。几千名散落在世界各地的开发者,凭借着脆弱的互联网建立关系,他们利用业余时间,构建出了一个鬼斧神工般的操作系统,随即这个系统又成为互联网的基石,其间沧海桑田,让人叹为观止。

一切都源于开放的态度。我对这一点深有体会,从写下第一条 MacTalk 推送开始,我只想向世界传递我的讯息,结果各种有趣的人和事纷至沓来。但行好事,莫问前程。

为什么要登山?因为山在远方。为什么要阅读?因为历史在书里。为什么要写作?因为思想流淌在心头和指尖。就是如此。

5、如果你对一件事情不感兴趣了,最好的做法是找到一个有能力的接棒者

每个人的兴趣都会转移,林纳斯也不例外。在 Linux 进入稳定发展的阶段,他把更多的精力放到了开源社区上,但是这并没有降低 Linux 操作系统的代码质量,因为他找到了更多的顶级源代码贡献者。

在软件开发的项目中我们同样会遇到类似的问题。某个功能的开发者突然对该功能失去了兴趣,这时候我们就有责任为这个功能找到一个可以胜任的接棒者,而不是强迫原来的开发者在原地踏步。

很多时候,我们厌倦了一件事情,并不是能力缺失,而是因为已经洞悉了这件事的所有秘密,于是转身离去,开辟新的征程……

6、把早期用户当做你的合作者或开发者,这是提高代码质量和产品质量的有效途径。

林纳斯把 Linux 的源代码放到网上之后,很快就收获了一批既是开发者又是合作者的用户,他选取了其中五人组成了核心开发小组,除了 Linux 内核建设的最终决定权属于林纳斯之外,一切都是开放的,这五个人承担了绝大多数关键的开发和组织工作,在各自的领域组织自己的用户和开发者,推进 Linux 有条不紊的向前发展。

这些合作者和开发者就像筑巢的蜂群一样,围绕着 Linux 辛勤的工作,看起来杂乱无章,实际上细致严密,因为任何人的工作都在阳光下进行,没一个错误的产生和修复是隐藏在暗影中的。一个人的代码出了漏洞,立刻有另一个人冲上去打补丁,打完之后,两人交换眼神,握手,然后转身投入下一轮的开发和测试中。

通常一个几十人的项目组就能把整个公司搞的鸡犬不宁,这种事我们见的太多了,但是林纳斯却依赖自己的早期用户构建了历史上最大的合作项目,成千上万的开发者依赖邮件列表和相互之间制定的规则进行交流和研发,同时开展的项目经常超过4000个。

如果你找到了产品的早期合作者用户,那么你的项目已经成功了50%。 「即便是高层次的设计,如果能有很多合作开发者在你产品的设计空间周围探索,也是很有价值的。设想下一滩雨水是怎么找到下水口的,或者说蚂蚁是怎么发现食物的。探索在本质上是分散行动,并通过一种可扩展的通信机制来协调整体行为。一个外围的游走者可能会在你旁边发现宝藏,而你可能有点过于专注而没能发现」。

现在很多创业项目在早期发布的时候常常采用邀请制,这其实是获取早期合作者用户的最佳时期,合理的选择用户并通过邮件列表、群组和线下交流活动等方式不断获取反馈,并让用户参与其中,会大大提高你的产品质量和代码质量。我参与过的早期项目中,有道云笔记·协作版算是做的不错的,可惜的是,产品版本正式发布之后,这种参与和反馈感渐渐消失了。

更多的创业产品只是把邀请用户当做普通用户看待,意义寥寥。正确的做法应该是把所有潜在的合作者用户加入你的邮件列表或特定群组,每次发布新版本时,向邮件列表发送朋友对话般的通知(而不是例行邮件),鼓励他们参与,听取他们的意见,征求他们关于设计决策的看法,当他们发来补丁和反馈时给他们以热情回应。

你会有回报的。

7、最好的领导就是「不要试图去领导」

林纳斯是一个懒惰的程序员,所以他很早就认识到,好的领导者,并不是大包大揽,也不是让下属去完成领导部署的任务,而是让他们做自己真正想做的工作。好的领导者不应该总是去试图领导别人,他们要及时反思,修正自己的思路和决策,听取别人的意见,并把一些决策权交给他人。

作为整个 Linux 项目的领军人物,林纳斯只是在操作系统内核的争端上进行仲裁和决策,其他时候,大部分是集思广益,多头并进。林纳斯说:

我有时会赞同他们的工作,有时会批评他们的工作,但是大多数时候我都是放任自流的。如果两个人同时维护了相同的功能,我会接受两份工作成果,评估哪一份更可行。如果两者竞争激烈,那么我会同时拒绝他们,直到其中一位开发者失去了兴趣。

如果你是一位创业公司的领军人物,要常常反思的不是「我是不是做的太少了」,而是「我是不是管的太多了」。

8、及早发布,快速发布,并倾听用户的声音

很多人都习惯性的认为,除非是很小的项目,早发布和频繁发布的做法有益无害。因为早期产品大都问题多多,过早发布会耗尽用户的耐心和开发者的雄心。这种看法直到互联网时代才开始有所改变。各大互联网公司为了抢占先机,开始无快不破,虽然第一代产品存在很多问题,但是他们会通过迅猛的迭代速度,快速推出第二代和第三代产品去弥补缺陷、赢得用户和占领市场。

其实这种策略 Linux 系统在上个世纪90年代就开始采用了,林纳斯在早期(1991年)发布内核的频率甚至超过了一天一次!他把用户当做了自己的合作者,他不断倾听用户的声音,以持续发布来回报用户,用自我满足感激励那些黑客和顶尖高手。有些人会提出问题,有的人会发现问题,有的人会解决问题,这一切都会淹没在 Linux 频繁发布的版本浪潮里……

当然,在那个年代,林纳斯能做到这一点,和他自己的才能与设计天赋不无关系。《大教堂和集市》一书中对林纳斯的描述是:

他更像是一个工程实施上的天才,他具备一种避免 bug 和防范开发走入死胡同的第六感,而且有一种能发现从 A 点到 B 点最省力路径的真本事,事实上,Linux 的整个设计,都透露着这种特质,并反映了林纳斯那种本质上保守而简洁的设计取向。

在移动互联网时代,及早发布、快速发布还会带来另一个附加值:如果你的 App 能够一周更新一次,那么用户永远不会忘记这些 App 和开发者,他们知道这些 App 的后面有一群鲜活的生命在不断的进行产品改进、性能调优、功能增强,通过频繁的发布,用户是能够感知到这些数据之外的东西,并给你丰厚的回报。

9、如果一个问题解决不了,那么要问问自己,是不是提出了正确的问题。

当你发现自己在开发中四处碰壁的时候,当你发现自己苦苦思索也难以确定下一个特征的时候,当你发现自己辗转腾挪也无法解决一个老问题的时候……停下来,喝杯咖啡吹吹风,你会发现,过了今天问题还是解决不了。

通常这时候,你不该再问自己是否找到了正确答案,而是是否提出了正确的问题,也许是问题本身需要被重新定义。

在不损失效能的前提下,不要犹豫,扔掉那些过时的特性吧。为了挽救 IE6的用户,还不如去为那些愿意使用高级浏览器(支持 HTML5)的用户提供更好的服务。

10、设计上的完美并不是没有东西可以加了,而是没东西可以减。

有时候,我们在软件设计的时候会尽可能让自己表现的聪明而有原创性,这让我们在前行的时候常常忽略那能够直达目的地的小径,我们被蓝色湖泊上飘荡着雾气吸引,在高山上怒放的美丽花朵之间徜徉,而忘记了真正的目标。

在应该保持软件健壮性和简单性的时候,设计者常常下意识把它弄得既华丽又复杂。应该用自动内存管理的时候使用了引用计数,能够最简实现的时候使用了各种设计模式,也许在潜意识里,很多程序员认为,使用了复杂技巧并难以读懂的代码才是好代码。

对于产品的设计和实现来说,增加功能和代码是最容易做到的,反而是代码减无可减,功能砍无可砍,最难实现。如果你的产品减少任何一个功能都会带来完整性和体验缺失的话,这款产品的功能就已经接近完美了,代码同样如此。

无论是产品设计还是编程实现,永远记住这样一个原则:KISS (keep it simple and stupid),简单即为美。

……

Linux 可以说是 IT 发展史上圣杯级别的产品,它的故事没有终点。几十年过去了,Linux 散落在历史长河中的点点滴滴,依然像耀眼的珍珠一样在时间的深水河中发出璀璨的光芒。如果你是一个开发者,多读读 Linux 相关的技术书;如果你是互联网从业者,多读读 Linux 相关的故事和传奇。如果你两者都不是,多读读 MacTalk 就好了。


Mac 软件之 iTerm2 再配置

前几天转载了一篇开始用iTerm2的,本来有这么多好处已经很满足了。奈何又看到了好几篇讲#iTerm2 #zsh #oh-my-zsh #guake什么的,感觉很强大但是自己又很懒,也没有按照大家推荐的搞。目前的结果就是,alt+空格自动显示界面,使用screen保存工作进度,使用alias简化切换过程。

不折腾其它的原因是自己只是很口水从顶部拉出的效果。诸如主题的自己一直在用django,内容保存用screen也已经习惯,没再深入了。

完成品就是这样了。

iTerm2-2

配置参照了这篇文章《mac下超好用的终端–iterm2用法与技巧》——CSDN.net

iTerm2-2

1 设置窗口

定位到 [Preferences - Profiles - Window] 新窗口设定风格设为 [Top of Screen],这样每次新打开终端都会固定出现在屏幕的顶端且不会有窗口边框。

iTerm2-2

2 设置快捷键

这一步很简单,定位到 [Preferences - Keys - Hotkey],这里有两个选项,第一个为设置全局快捷键,在 iTerm 启动的前提下,使用该快捷键可显示或隐藏窗口。第二个指定新窗口使用哪个 Profile,这里就指定为在 Step1 中设置了 WIndow 的那个即可,勾选这个选项能获得显示/隐藏窗口时淡入淡出的技能。

iTerm2-2

3 随时响应

完成上面两步,在 iTerm 已经启动的情况下就能够完成本文最开始GIF中那样的效果了。但是这样还不够,要让其随时响应,就需要 iTerm 随时保持在启动状态。在 OSX 系统账户设置中添加 iTerm 为登录启动项即可.

4 隐藏 Dock 图标

/usr/libexec/PlistBuddy  -c "Add :LSUIElement bool true" /Applications/iTerm.app/Contents/Info.plist

这个方法是通用的,LSUIElement1可控制 app 以无Dock,无菜单栏的方式运行,另外LSBackgroundOnly2可让 app 以无窗口的方式在后台运行。详细说明可查看 LaunchServicesKeys

如果要恢复 Dock 图标:

/usr/libexec/PlistBuddy  -c "Delete :LSUIElement" /Applications/iTerm.app/Contents/Info.plist

5 本地alias

配置 ~/.bashrc 或者 /etc/bashrc

alias ss='ssh anythingyulike'

6 本地ssh

配置 ~/.ssh/config

Host anythingyulike
    	HostName xxx.com
    	Port xxxx
    	User youruser
    	IdentityFile ~/.ssh/youruser

7 远端alias

配置 ~/.bashrc 或者 /etc/bashrc

alias ss='screen -d -r'
alias s1='screen -S lu'
alias s2='screen -S ld'
alias s3='screen -S rd'
alias s4='screen -S ru'
alias ss1='screen -d -r lu'
alias ss2='screen -d -r ld'
alias ss3='screen -d -r rd'
alias ss4='screen -d -r ru'
alias sll='screen -ls'

Linux下同步onedrive

最近入了台surface pro 3,微软附带送了1年的onedrive和skype的服务。skype倒还好可以无压力地用掉。onedrive就很头疼了,在本地上传传得地老天荒还没传完2%,百度云早就传完了。大概是onedrive对国内的用户还不够友好吧。

早上闲来无事,不知道怎么搞的便安装起了github上的一个项目onedrive-d,在linux下同步onedrive用的。折腾来折腾去总算是搞好了同步。

看到github上的一些issue,不少人使用onedrive-d仍然有一些问题,反应的,诸如每次开机会重新同步所有文件;并且有可能会将文件同步多次,形成多个同名文件。安装时候要做好一定的心理准备。

pip

按照习惯先说卸载时遇到的问题Orz

pip是python的软件安装工具。今天在卸载onedrive-d的时候出现了这个提示符pip:command not found。上官网找了好几遍竟然没找到下载地址,也真是醉了,竟然在一个不起眼的地方。

下载之后运行python get-pip.py安装pip。安装完成后就开始卸载onedrive-d,但是其实卸载还是会报错。把~/.onedrive删除后就不用管它,已经是卸载了= =。

安装

$ git clone https://github.com/xybu92/onedrive-d.git
$ cd onedrive-d
$ ./setup.sh --help

Usage ./setup.sh [inst|remove]
inst: install onedrive-d
remove: uninstall onedrive-d from the system

# 安装
./setup.sh inst

配置

按照上述步骤安装之后就算是安装成功了。

来看看代码的目录结构。

default  LICENSE  LiveAPI.md  onedrive_d  README.md  setup.sh

./default:
ignore_list.txt

./onedrive_d:
config.py    live_api.py  observer_gtk.py  pref.py      setup.py
daemon.py    logger.py    pref_cmd.py      __pycache__
__init__.py  main.py      pref_gtk.py      res

程序中有两个重要的命令,一个是预配置onedrive-pref,用来设定账户,另一个是onedrive-d,用来设定哪个文件需要同步的。

接下来使用onedrive-pref预配置。

$ onedrive-pref

不知道大家运行成功不,反正在Debian7.7下是没办法运行的

onedrive-pref: command not found

作者也说,他非正式版本还没吧命令添加进系统里!1.0正式版本也还没发布的样子= =所以直接运行

./onedrive_d/pref.py --no-gui

会给出一个连接,将这个链接粘贴到浏览器登陆到hotmail邮箱之后,将地址栏的信息粘贴回终端里,就完成账号绑定啦。

要退出账号也很简单,用下面这个命令退出。

./onedrive_d/pref.py --log-out

tips: 为了今后能够更快的运行命令,建议用~/.bashrc记录你的快捷命令。例如以下命令,设定之后记得source ~/.bashrc

alias onedrive-d='/home/github/onedrive-d/onedrive_d/main.py'
alias onedrive-prefs='/home/github/onedrive-d/onedrive_d/pref.py'

使用

然后在默认目录~/OneDrive下运行onedrive-d进行完全同步.

总结

目前我是暂时不用了,一来服务器没有那么大的空间同步,二来一不小心搞得自己以前的文件乱七八糟的,收拾起来也麻烦。


uebersicht - 一款漂亮的桌面Widgets

Übersicht 是Mac下一款可以用来自定义桌面插件的工具。我们可以根据自己的喜好定制不同的Widgets。和Windows下的Rainmeter类似。把玩了一下感觉棒棒的。

效果还真挺炫的。目前在想着可以给自己的服务器加一些状态接口,通过uebesicht方便简单又干脆就可以拿到服务器的实时数据,实在是居家旅行必备。

uebersicht

详细的介绍在少数派上有介绍,下面是转载文。

在相关的同类应用中,听说得比较多的当属 GeekTool 和人称「通知中心 GeekTool」的 Today Scripts 无疑,它们和 Übersicht 的运行原理基本相同,但后者的不同在于,它还支持 HTML5 和特殊的 CoffeeScript 语法,所以 它的优势就很明显了:

  • 相对轻松的编写和自定义过程。
  • 多元化的显示风格。
  • 主动适配不同屏幕尺寸的能力。

安装插件

Übersicht Widgets 的安装方法很简单,先在官网 下载安装 Übersicht ,然后前往 官方 Widget 商店 寻找自己想要的插件,点击 Banner 封面图可以读取相关开发者的介绍,或直接通过右下方 download 进行下载。接着,将解压缩后得到的 .coffee 文件置入 Übersicht Widgets 的文件夹即可(偏好设置中可以进行自定义)。稍等片刻,桌面插件就会被主程序自动读取,安装完成。

不过,有些插件的安装方法比较复杂,比如 Pretty Weather 这款。除了上述步骤,它还要求用户获取「天气数据」所需的个人 API Key,读者可以 点击 前往注册。接着,需要将 API Key 覆盖至源代码中的相关地址,方可正常显示天气数据。还有最后一步,就是获取你当前的位置信息,有条件的读者可以通过 Google Maps 获取。


配置mutt和msmtprc从debian中发邮件

服务器发送邮件主要有两种方式。一种是搭建一个MTA(邮件传输代理),使用sendmail或POSTFIX进行发送。具体的方法可以看Linode给的Guide,非常的详细。以这种方式搭建要考虑清楚自己是否真的需要一个邮件服务器,因为搭建的过程十分繁琐枯燥。Linode的文档也是一再强调这一点。另一种方式就是本文的mutt+msmpt。特点是轻量,够用。(υ◉ω◉υ)

安装

apt-get install mutt msmtp

配置mutt

/etc/Muttrc是全局的,也可以用在用户目录下~/.muttrc配置。

set sendmail="/usr/bin/msmtp"
set use_from=yes
set realname="kelu" # 发件人名字
set from=kelu@kelu.org # 发件人地址
set envelope_from=yes

set charset="utf-8"
#set send_charset="gb2312"
set send_charset="utf-8"
set locale = "zh_CN.UTF-8"
set content_type = "text/html\;charset=utf-8"

配置.msmtprc

同样,msmtprc也是可以在/etc/msmtprc或者用户目录下的~/.msmtprc进行配置。

account default
host smtp.163.com  --> email server 地址
from kelu@kelu.org
auth login # 用plain似乎也没问题?有空再看
user kelu@kelu.org
password kelu.org
logfile ~/.msmtp.log

.msmtprc文件需要600权限,如果不是600权限会无法使用

使用以上的配置已经可以使用一些普通的国内邮箱进行信息发送了。但是如果你使用了gmail的话,需要多做出一些配置才可以。以下是我的设置,配置的方法也是参考了不少网站才找到的。例如Virtage Devblog 最后正确的配置方法来自archlinux的bbs

# Default settings that all others account inherit
defaults

# Logging - uncomment either syslog or logfile, having both uncommented disables logging at all.
#syslog on
# Or to log to log own file
logfile  /var/log/msmtp.log

keepbcc  on

# Gmail/Google Apps (configure as may as you want)
account  gmail
host   smtp.gmail.com
port   587
protocol smtp
auth on
from pbrisbin@gmx.com
user pbrisbin@gmx.com
password XXXXX
tls on
tls_nocertcheck

# Default account to use
account default : gmail

一如那位配置好的用户所说的,works like a dream ʕ•̫͡•ʔ→ʕ•̫͡•̫͡•ʔ→ʕ•̫͡•=•̫͡•ʔ→ʕ•̫͡•ʔʕ•̫͡•ʔ→ʕ•̫͡•̫͡•ʔ ʕ•̫͡•̫͡•ʔ

发邮件给foo@google.com,并带有一个附件

mutt -s "主题" foo@google.com -a 附件.txt < 邮件内容.txt

扩展

配置好邮件之后就可以发送一些vps的状态邮件给自己啦,还有很多种可能性,比如流量突然升高啊,登陆ssh发邮件提醒啊之类的。

比如在/etc/ssh/sshrc中添加以下信息:

echo "$USER@`hostname` `date +%Y-%m-%d\ %H:%M` login from ${SSH_CLIENT%% *}" | mutt -s "$USER `date +%Y-%m-%d\ %H:%M` login from ${SSH_CLIENT%% *}" XXXXXX@kelu.org &

当有人登陆服务器时候发邮件提醒。


Linux命令之awk

本文大部分引用自《GAWK 入门:AWK 语言基础》- IBM developerWorks

Awk是一种处理结构数据并输出格式化结果的编程语言, Awk 是其作者 “Aho,Weinberger,Kernighan” 的简称。

Awk通常被用来进行格式扫描和处理。通过扫描一个或多个文件中的行,查看是否匹配指定的正则表达式,并执行相关的操作。awk 适合于文本处理和报表生成,它还有许多精心设计的特性,允许进行需要特殊技巧程序设计。awk 的语法较为常见。它借鉴了某些语言的一些精华部分,如 C 语言、python 和 bash(虽然在技术上,awk 比 python 和 bash 早创建)。awk 是那种一旦学会了就会成为您战略编码库的主要部分的语言。

主要特性

  • Awk以记录和字段的方式来查看文本文件
  • 和其他编程语言一样,Awk 包含变量、条件和循环
  • Awk能够进行运算和字符串操作
  • Awk能够生成格式化的报表数据

语法

Awk从一个文件或者标准输入中读取数据,并输出结果到标准输出中。

awk '/search pattern1/ {Actions}    
     /search pattern2/ {Actions}' file     * search pattern是正则表达式 * Actions 输出的语法 * 在Awk 中可以存在多个正则表达式和多个输出定义 * file 输入文件名 * 单引号的作用是包裹起来防止shell截断

工作方式

  • Awk 一次读取文件中的一行
  • 对于一行,按照给定的正则表达式的顺序进行匹配,如果匹配则执行对应的 Action
  • 如果没有匹配上则不执行任何动作
  • 在上诉的语法中, Search Pattern 和 Action 是可选的,但是必须提供其中一个
  • 如果 Search Pattern 未提供,则对所有的输入行执行 Action 操作
  • 如果 Action 未提供,则默认打印出该行的数据
  • {} 这种 Action 不做任何事情,和未提供的 Action 的工作方式不一样
  • Action 中的语句应该使用分号分隔

默认行为

默认的时候awk 打印文件中的每一行

$ awk '{print;}' hello.txt 

由于匹配的正则表达式未给出,因此后续的Action 适用所有的行, Action 中的 print 没有任何参数的情况下将打印整行,注意其中的 Action 必须使用 {} 括起来。

操作符(awk操作符与C语言类似)

+        加
-        减
*        乘
/        除
%        取余
^        幂运算
++        自加1
--        自减1
+=        相加后赋值给变量(x+=9等同于x=x+9)
-=        相减后赋值给变量(x-=9等同于x=x-9)
*=        相乘后赋值给变量(x*=9等同于x=x*9)
/=        相除后赋值给变量(x/=9等同于x=x/9)
>        大于
<        小于
>=        大于等于
<=        小于等于
==        等于
!=        不等于
~        匹配
!~        不匹配
&&        与
||        或
  ^2 			#2次方
  **2			#2次方
函数名称 返回值
atan2(x,y) y,x范围内的余切
cos(x) 余弦函数
exp(x) 求幂
int(x) 取整
log(x) 自然对数
rand() 随机数
sin(x) 正弦
sqrt(x) 平方根
srand(x) x是rand()函数的种子

BEGIN 和 END

BEGIN { Actions}    
{ACTION} # Action for everyline in a file    
END { Actions }  

在BEGIN 节中的 Actions 会在读取文件中的行之前被执行。

而END 节中的 Actions 会在读取并处理文件中的所有行后被执行。 awk 非常善于处理分成多个逻辑字段的文本,而且让您可以毫不费力地引用 awk 脚本中每个独立的字段。

# 使用 -F 选项来指定 ":" 作为字段分隔符。
$ awk -F":" '{ print "username: " $1 "/t/tuid:" $3" }' /etc/passwd 

外部脚本

将脚本作为命令行自变量传递给 awk 对于小的单行程序来说是非常简单的,而对于多行程序,它就比较复杂。您肯定想要在外部文件中撰写脚本。然后可以向 awk 传递 -f 选项,以向它提供此脚本文件。

$ awk -f myscript.awk myfile.in
# 只打印包含浮点数的行。
/[0-9]+/.[0-9]*/ { print }
	
# 如果当前行的第一个字段不等于 fred,awk 将继续处理文件而不对当前行执行 print
$1 == "fred" { print $3 }
	
#如果某一行的第五个字段包含字符序列 root,那么将只打印这一行中的第三个字段
$5 ~ /root/ { print $3 }

条件语句

awk 还提供了非常好的类似于 C 语言的 if 语句。如果您愿意,可以使用 if 语句重写前一个脚本:

# 如果某一行的第五个字段包含字符序列 root
{
	if ( $5 ~ /root/ ) {
	print $3
	} else {
	}
}
awk 还允许使用布尔运算符 “   “(逻辑与)和 “&&”(逻辑或),以便创建更复杂的布尔表达式。只打印第一个字段等于 foo 且第二个字段等于 bar 的那些行。
( $1 == "foo" ) && ( $2 == "bar" ) { print }

内置变量

ARGC        命令行参数个数
FILENAME    当前输入文档的名称
FNR        当前输入文档的当前记录编号,尤其当有多个输入文档时有用
NR        总行数
NF        当前记录的字段个数
FS        字段分隔符
OFS        输出字段分隔符,默认为空格
ORS        输出记录分隔符,默认为换行符\n
RS        输入记录分隔符,默认为换行符\n		 默认awk读取数据以空格或制表符作为分隔符,但可以通过-F或FS(field separator)变量来改变分隔符。

变量传递

shell传入awk

1.”‘$var’”

#!/bin/bash
var="test"
awk 'BEGIN{print "'$var'"}'

这种写法要求变量var中不含有空格。若var中含有空格,那么就要用 “‘“$var”’”

2.export变量,然后用ENVIRON[“var”]

#!/bin/bash
var="test"
export var
awk 'BEGIN{print ENVIRON["var"]}'

3.使用-v选项。

#!/bin/bash
var="test"
awk -v nvar="$var" 'BEGIN{print nvar}'

awk传入shell

1.让awk将变量值按一定格式输出到STDOUT上,然后由shell解析 2.eval

$ unset a
$ eval $(awk 'BEGIN{print "a=1"}')
$ echo $a

#!/bin/bash
var1="test"
var2="along"
eval $(awk 'BEGIN{print "var1=along;var2=test"}')
echo "var1:"$var1
echo "var2:"$var2
./awktest.sh 
var1:along
var2:test

关于eval的用法血衫今后再写一下。

例子

awk  '/^$/ {print x+=1}'   test.txt                    备注:统计所有空白行
awk  '/^$/ {x+=1}  END {print x}'   test.txt        备注:打印总空白行个数
awk -F:  '$1~/root/   {print  $3}'   /etc/passwd     备注:打印root的ID号
awk -F:  '$3>500  {print  $1}'      /etc/passwd     备注:列出计算机中ID号大于500的用户名
awk 'BEGIN { x="123"; print x-2 }' #将字符串转换为数值来运算
awk 'BEGIN {sum=0} {sum+=$0} END{print sum/FNR}' file.txt # 求平均数

docker images -a | awk '{ print $1":"$2 }'  # 打印所有镜像名

分组求平均:
awk -F" " '{sum2[$1] += $2; sum3[$1] += $3; cnt[$1] += 1} END{for (i in sum2) print i, sum2[i]/cnt[i], sum3[i]/cnt[i]}' gav.txt

邮件中的html - 阮一峰

本文来自阮一峰的网络日志HTML Email 编写指南

今天,我想写一个”低技术”问题。

话说我订阅了不少了新闻邮件(Newsletter),比如JavaScript Weekly。每周收到一封邮件,了解本周的大事。

image

有一天,我就在想,是不是我也能做一个这样的邮件?

然后,就发现这事不那么容易。抛开后台和编辑工作,单单是设计一个Email样板,就需要不少心思。

image

因为这种带格式的邮件,其实就是一张网页,正式名称叫做HTML Email。它能否正常显示,完全取决于邮件客户端。大多数的邮件客户端(比如Outlook和Gmail),会过滤HTML设置,让邮件面目全非。

我发现,编写HTML Email的窍门,就是使用15年前的网页制作方法。下面就是我整理的编写指南。

1. Doctype

目前,兼容性最好的Doctype是XHTML 1.0 Strict,事实上Gmail和Hotmail会删掉你的Doctype,换上这个Doctype。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

 <head>

  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

  <title>HTML Email编写指南</title>

  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>

 </head>

</html>

使用这个Doctype,也就意味着,不能使用HTML5的语法。

2. 布局

网页的布局(layout)必须使用表格(table)。首先,放置一个最外层的大表格,用来设置背景。

<body style="margin: 0; padding: 0;">

 <table border="1" cellpadding="0" cellspacing="0" width="100%">

  <tr>
   <td> Hello! </td>
  </tr>

 </table>

</body>

表格的 border 属性等于1, 是为了方便开发。正式发布的时候,再把这个属性设为0。

在内层,放置第二个表格。用来展示内容。第二个table的宽度定为600像素,防止超过客户端的显示宽度。

<table align="center" border="1" cellpadding="0" cellspacing="0" width="600" style="border-collapse: collapse;">

 <tr>
  <td> Row 1 </td>
 </tr>

 <tr>
  <td> Row 2 </td>
 </tr>

 <tr>
  <td> Row 3 </td>
 </tr>

</table>

邮件内容有几个部分,就设置几行(row)。

3. 图片

图片是唯一可以引用的外部资源。其他的外部资源,比如样式表文件、字体文件、视频文件等,一概不能引用。

有些客户端会给图片链接加上边框,要去除边框。

  img {outline:none; text-decoration:none; -ms-interpolation-mode: bicubic;}

  a img {border:none;}

  <img border="0" style="display:block;">

需要注意的是,不少客户端默认不显示图片(比如Gmail),所以要确保即使没有图片,主要内容也能被阅读。

4. 行内样式

所有的CSS规则,最好都采用行内样式。因为放置在网页头部的样式,很可能会被客户端删除。客户端对CSS规则的支持情况,请看这里。

另外,不要采用CSS的简写形式,有些客户端不支持。比如,不要写成下面这样:

  style="font: 8px/14px Arial, sans-serif;"

如果想表达

  <p style="margin: 1em 0;">

要写成下面这样:

  <p style="margin-top: 1em; margin-bottom: 1em; margin-left: 0; margin-right: 0;">

5. W3C校验和测试工具

要保证最终的代码,能够通过W3C的校验,因为某些客户端会把不合格属性剥离。还要使用测试工具(1, 2, 3),查看在不同客户端的显示结果。

发送HTML Email的时候,不要忘记MIME类型不能使用

  Content-Type: text/plain;

而要使用

  Content-Type: Multipart/Alternative;

发送工具可以考虑使用 MailChimpCampaign Monitor

6. 模板

使用别人已经做好的模板,是一个不错的选择(这里这里),网上还可以搜到更多

自己开发的话,可以参考HTML Email BoilerplateEmailology

7. 参考链接

进一步研究,请参考下面的文章。

  - Sean Powell,Say Hello to the HTML Email Boilerplate

  - Nicole Merlin,Build an HTML Email Template From Scratch

  - Nicole Merlin, What You Should Know About HTML Email

(完)


1 2 3 4 5 156 157 158 159 160