Unix/Linux命令行小技巧(4)- 显示文本文件内容的行号

使用cat -n /file命令可以显示文本文件内容的行号:
举个例子:

[root@localhost command]# cat -n ./mem1.log
 1               total       used       free     shared    buffers     cached
 2  Mem:         32062       9922      22140          0        906       3451
 3  -/+ buffers/cache:       5563      26498
 4  Swap:        31999       9313      22686

技巧出处:https://twitter.com/nixcraft/status/188694159203373056

Unix/Linux命令行小技巧(3)- 把命令输出到多个日志文件

可以使用tee命令把命令输出到多个日志文件:
举个例子:

[root@localhost command]# free -m | tee mem1.log mem2.log
         total       used       free     shared    buffers     cached
Mem:         32062       9922      22140          0        906       3451
-/+ buffers/cache:       5563      26498
Swap:        31999       9313      22686
[root@localhost command]# ls
mem1.log  mem2.log
[root@localhost command]# ls -alt
total 16
drwxr-xr-x  2 root root 4096 Jan 12 10:48 .
-rw-r--r--  1 root root  230 Jan 12 10:48 mem1.log
-rw-r--r--  1 root root  230 Jan 12 10:48 mem2.log
drwxrwxrwx 15 root root 4096 Jan 12 10:47 ..
[root@localhost command]# cat mem1.log
             total       used       free     shared    buffers     cached
Mem:         32062       9922      22140          0        906       3451
-/+ buffers/cache:       5563      26498
Swap:        31999       9313      22686
[root@localhost command]# cat mem2.log
             total       used       free     shared    buffers     cached
Mem:         32062       9922      22140          0        906       3451
-/+ buffers/cache:       5563      26498
Swap:        31999       9313      22686

可以看到,mem1.logmem2.log文件都保存了日志。
技巧出处:https://twitter.com/nixcraft/status/163974717311692801

 

Unix/Linux命令行小技巧(2)- Linux上kill占用某端口的进程

Linux平台上kill占用某端口进程命令:

fuser -k port/tcp(udp)

举个例子:

[root@localhost redis-2.8.19]# ps -ef | grep redis
root     10049 35207  0 17:33 pts/7    00:00:00 ./src/redis-server *:6379
root     10116 35207  0 17:33 pts/7    00:00:00 grep redis             
[root@localhost redis-2.8.19]# fuser -k 6379/tcp
6379/tcp:            10049
[1]+  Killed                  ./src/redis-server

可以看到,占用6379端口的进程被杀死了。
技巧出处:https://twitter.com/nixcraft/status/162914646125330432

Unix/Linux命令行小技巧(1)- 显示运行进程的PID

Bash中定义如下函数(函数参数为程序名):

findpid() { ps axc|awk "{if (\$5==\"$1\") print \$1}"; }

执行效果:

[root@localhost ~]# findpid() { ps axc|awk "{if (\$5==\"$1\") print \$1}"; }
[root@localhost ~]# findpid tail
16049
25206
40701
48132

技巧出处:https://twitter.com/nixcraft/status/158835574508240896

小评《理解Unix进程》

双“十一”期间参加CSDN活动,中了一本《理解Unix进程》,这两天花时间看完了。简单谈一下对这本书的的评价,谨代表个人意见。

这本书很薄,只有100来页,分为20章还有4节附录,这就表明每一章内容不是很多。书中的示例是用ruby语言写的,但是我相信大家都能看懂,不需要对ruby有很深的了解。总体来讲,这本书还是讲解了很多关于Unix的知识点,可以作为参考手册,或者可以在上下班的车上抽空读一读。不管是新手还是老兵,个人觉得都值得一看。价格也还好,20多元,应该不算贵。

另外,如果本身就是ruby程序员的,我非常推荐,应该会给你一些帮助!

Windows/Unix文本格式转换导致“/usr/bin/env: No such file or directory”

今天在用同事写的一个python脚本,一运行就出现了以下错误:

/usr/bin/env: No such file or directory

用ls命令查看了一下,“/usr/bin/env”明明存在:

bash-3.2# ls -lt /usr/bin/env
-r-xr-xr-x 1 root bin 5780 Jan 23  2005 /usr/bin/env

用vi打开这个python脚本,第一行显示:

#!/usr/bin/env python^M

又是一个Windows/Unix文本格式转换问题。用dos2unix转换好以后,运行OK!

P.S. 请参考stakoverflow这个问题:http://stackoverflow.com/questions/3598592/invoking-perl-scripts

UNIX/Linux C 程序员需要掌握的七种武器

我是一名普通的软件工程师,不是什么技术大牛。这篇文章所提到的“七种武器”只是我这些年工作经验的一点体会和感悟,如果有错误的地方,还请大家指正。

(一)C语言
作为一名C程序员,熟练掌握C语言是最基本的一项技能。关于如何学好C语言,以及C语言话题的讨论,网上有很多经典的文章,我就不一一列举了。在这里,我只想谈一点我个人的体会:刚毕业时,我来到一家比较大的软件公司工作,而公司的工作模式是每个人只负责一个小模块。这样工作两年后,我自认为我的C语言水平已经很高了。后来,我来到现在这家公司。由于工作需要,接触的东西也多了,开源项目也了解一些,才发现自己的C语言能力太一般了:原来宏可以这样写,指针可以这样用…等等。现在我在写代码时,常常会想:这个行为是C语言规范定义的吗?如果是,是C89还是C99?我现在用的编译器支持吗?如果不是C语言规范定义的,那么在程序运行的这个平台,行为是确定的吗?所以我建议大家平时可以多想想这些问题,查查资料,相信一定会对C语言有更深的理解。

(二)UNIX/Linux系统编程
在UNIX/Linux系统上开发程序,掌握系统编程API是必不可少的技能。而这方面的经典书籍都是一些大部头的英文著作,让人望而生畏。在这里,我谈一点自己的建议:我觉得可以先找一本口碑不错的中文书先看一下,了解一下都有哪些种类的API。这样以后用到时,再去精读经典英文著作里的相关章节,或是查man手册。此外,我觉得如果有时间,可以学习一下经典的开源项目,了解这些开源项目是如何使用这些API的。举个例子,Redis是很多人推荐的一个很不错的学习C语言的开源项目。我在阅读代码时,看到保存数据到文件时会用到fsync函数,我就会去深入地了解一下这个函数的作用。这样比单纯地去看那些著作效果要好。

(三)网络编程及相关知识
关于网络方面,我想从以下三点分享一下我的体会:
a)网络协议。在日常的工作中,大家接触和使用最多的无疑是TCP/IP协议族。此外,由于工作领域不同,也可能用到其它的协议。比方说,我主要做电信相关的程序开发,平时可能接触SCTP协议会更多一些。对于这些协议,我觉得掌握最基本的知识是必须的,其它的边边角角知识可以等到用时再查。举例来说,TCP协议的“三次握手”,“四次挥手”,“TIME-WAIT状态”这些基本的知识点要弄明白,其它的边角知识学完老不用忘得也快,还是用时google一下效率更高。
b)Socket编程。Socket编程的经典书籍一点不比讲系统编程的书薄,所以可以选一本相对薄点,口碑不错的精读一下,这样基本就掌握的百分之五、六十了。另外有时间还是看一下经典的开源代码。这里还拿Redis举例,Redis里关于处理网络连接和通信的代码量不大,而且基本涵盖了所有常见的UNIX平台,看完以后一定受益匪浅。
c)协议分析工具。TCPdump、snoop(Solaris平台工具)、wireshark等这些工具不仅能帮助我们抓取数据包,还能分析数据包,这对debug网络程序有非常大的帮助。所以,我们至少要掌握这些工具最常用的功能。此外,对于开放源代码的工具,我们更是可以从代码中学到很多知识。举例来说,我做短信相关的项目,就从wireshark的分析短信协议的代码里学到了很多东西,这使我对短信协议有了更清晰的理解。

(四)脚本编程能力
一提到脚本编程,大家首先想到的可能就是Bash shell脚本编程了。不错,在Unix/Linux上,Bash shell也许就是用的最广泛的脚本编程语言。我平时主要用Bash shell做两个方面的工作:a)用于编写监控服务脚本;b)写一些简单的单元测试脚本,比如循环发一些命令,等等。但是Bash shell的功能远远要比这些强大。我见过一些高手用Bash shell编程语言写出了很好玩的游戏,也有人做出了很cool的网络应用。所以建议大家有兴趣可以多了解一下Unix/Linux的这层“壳”。当然,你也可以选择学习Python、Perl、Ruby等。不过相比这些语言,Bash shell至少你不用自己去安装,而且它能做的事同样很强大。

(五)操作系统及CPU体系结构
也许有一天,你会碰到这样的情景:你的程序在Solaris上会发生core dump,在Linux上却运行的好好的。经过一番艰苦的debug,最后得到的原因是两种操作系统对线程的调度策略不一样,这会使一个对全局变量没有加锁就访问的bug在Linux上很难出现。所以你需要尽可能地去了解你使用的操作系统,这样无论对写程序还是debug都会有很大的帮助。比如,你需要了解进程的内存布局,这样你就知道栈和堆到底在内存的哪段空间,为什么内存写越界有时会core dump,有时没事。
除了操作系统,了解CPU的体系结构也是一门必修课。比方说,SPARC CPU要求字节对齐,而X86 CPU则没有这个要求。又比如SPARC CPU是大端模式,而X86 CPU是小端模式,这就要求你对像位域这样的定义要格外小心。你还要了解你使用的CPU的汇编语言,至少能大概看懂。因为有些时候,当你从C代码中找不出bug的原因时,就需要你“透过现象看本质”,从汇编代码层面看看到底发生了什么。

(六)编译器和调试器
“工欲善其事,必先利其器”。编译器负责把源代码生成可执行文件,而调试器则是在程序出现bug时,用来“降妖除魔”的不二神器。我会以我最熟悉的gcc和gdb为例子,来谈一下个人体会。
gcc有很多编译选项,除了要熟悉像-O,-g这些最基本的选项,我建议大家可以多了解一些其它不常见的选项。因为这些选项很可能帮助我们找到程序的一些bug。举个例子,在比较新的gcc版本里,增加了-fstack-protector这个选项,而它可以帮助我们检查到缓冲区溢出这种bug。此外,你还可能碰到这种情况,一个bug总是发生在程序优化后的版本,而不会出现在没经过优化的版本。所以,多了解你的编译器,你就可以更好地了解你的程序是如何生成的。
一个程序员不可能不碰到bug,而这个时候,调试器就是最好的工具。可以说,在遇到bug时调试技巧和手段是否丰富是衡量一个程序员的能力和水平的重要参考。除此以外,gdb另一个重要用途就是分析程序的core dump文件。我个人很喜欢看破案和推理的电视节目。我觉得程序的core dump文件可以比作“犯罪现场”,而gdb就是公安人员用来在现场提取线索的工具。对gdb越熟悉,就越能从core dump文件提取有价值的信息,也就越有助于我们定位到程序bug的“root cause”。

(七)DTrace/SystemTap
DTrace是由Sun的几位才华横溢的工程师开发的,最开始只支持Solaris操作系统,现在FreeBSD和Mac OS X也都支持了。Linux上类似的工具有SystemTap,也有人把DTrace移植到Linux上,不过效果似乎并不好。简单地说,DTrace可以几乎不会在对整个系统有任何性能影响下,让你了解你的程序所发生的一切。这对分析程序的热点(“Hot spot”),了解程序的执行流程,定位程序bug都有很大的帮助。有些时候,DTrace可能是你唯一的工具。举例来说,有个程序只发生在生产环境,而在实验室环境无法复现(当然,理论上任何bug都可以复现,只是我们没有找到复现条件。)。你不可能在你怀疑的代码打上断点,然后用gdb去调试。这时你只能借助于DTrace,通过它去了解程序到底是如何运行的,当时的变量值是什么。此外,DTrace还可以帮你了解操作系统的kernel,这会满足很多geek的好奇心。

以上就是我总结的UNIX/Linux C 程序员需要掌握的“七种武器”,同时也很感谢你能耐心地读完这篇文章。如果这篇小文没有让你觉得浪费时间,而是对你有哪怕一点小小的帮助,我的目的也就达到了。如果你有一些好的观点,也非常欢迎你能分享出来。谢谢!

Chinaunix论坛“Linux/UNIX系统编程,系统程序员成长的基石?”话题讨论的回复

以下是我参与Chinaunix论坛关于“Linux/UNIX系统编程,系统程序员成长的基石?”(http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=4118545&fromuid=28864581)话题讨论的回复,整理出来发到这里,给需要的人做个参考:

(1) 您在Linux/UNIX系统编程行业的经历及经验
我是2006年研究生一年级时开始接触Linux系统编程的,当时是因为我实习的公司用到Linux。后来自己在业余时间看了一些系统编程方面的书,还实现了一个简单的网络协议。通过研究生这两年的经历,算是对Linux系统编程有了一个入门。2008年研究生毕业后,并没有从事Linux/UNIX系统编程的相关工作,而是做手机MMI程序的开发。2010年来到现在这家公司,才又重新开始Linux/UNIX系统编程的工作,目前我主要在Solaris/Linux系统上从事通信网关和服务器程序的开发。通过这些年的经历,我觉得从事Linux/UNIX系统编程最大的益处就是可以获得很多计算机底层系统的知识。举几个例子来说:通常我们都使用gcc编译器编译程序,我们需要了解一些常用编译选项的含义,因为有可能一个编译选项就会导致程序不按你的想法运行;程序不可能没有bug,也许我们需要gdb帮助我们详细了解程序的内存布局,去找到原因;有时程序在一个处理器上运行的好好的,而在另一个上面就不行,此时我们可能又要去了解处理器结构和汇编语言。总之,作为一个底层软件工程师,需要不断地学习计算机最底层最核心的技术,这是件很快乐的事情。

(2) Linux/UNIX系统编程职业生涯的发展探讨
最近几年,随着移动互联网的兴起,前端技术越来越受到大家的重视,而底层技术似乎现在的关注度并不高。我个人觉得Linux/UNIX系统编程知识是程序员的重要基础,无论你从事什么方面的开发,了解系统编程知识和原理,对你是有百益而无一害的,Linux/UNIX系统编程也永远不会被淘汰。所以,我们这些Linux/UNIX系统编程工程师需要做的就是不断学习,提高自己的技术能力。

(3)对于新入门的Linux/UNIX系统编程人员来说,您有什么话对他们说?
我并不是一个资深的工程师,以下是我个人的一点经验和体会,希望给大家一点启示吧:
首先要调整好心态,现在是个浮躁的社会,所以要尽量着让自己静下心来,踏踏实实地去学习技术。
第二就是多实践,经典的技术书籍很多,可是光是阅读,效果并不好。要试着自己写一些代码,这样会加深印象。
第三就是多读好的开源代码。现在github上有很多的优秀代码值得我们学习。拿著名的NoSQL数据库Redis来说,看完Redis的main函数,我们就可以了解到如何创建一个deamon进程了,此外我们也会从中学到如何写个好的高并发服务器程序,如何访问文件系统等等。

以上是我的一孔之见,希望能给大家一点帮助吧。