【转载】Unix设计哲学 & 回车换行八卦 & EOF八卦 & UNIX目录结构八卦

昨天看了这篇文章 《关于Unix哲学

首先用了两个例子,用风扇吹出空肥皂盒 和 太空铅笔,来说明简单设计也能派上作用吧。

 

Unix哲学,Wikipedia上列出了好几个版本,不同的人有不同的总结。发明管道命令的Doug McIlroy总结了三条,而Eric S. Raymond则在The Art of Unix Programming一书中,一口气总结了17条。

但是所有人都同意,"简单原则"----尽量用简单的方法解决问题----是"Unix哲学"的根本原则。这也就是著名的KISS(keep it simple, stupid),意思是"保持简单和笨拙"。

 

如果你想最简单地完成一项编程任务,我认为可以从四个方面入手:

 

1. 清晰原则。
代码要写得尽量清晰,避免晦涩难懂。清晰的代码不容易崩溃,而且容易理解和维护。重视注释
不为了性能的一丁点提升,而大幅增加技术的复杂性,因为复杂的技术会使得日后的阅读和维护更加艰难。
2. 模块原则。 每个程序只做一件事,不要试图在单个程序中完成多个任务。在程序的内部,面向用户的界面(前端)应该与运算机制(后端)分离,因为前端的变化往往快于后端3. 组合原则。 不同的程序之间通过接口相连。接口之间用文本格式进行通信,因为文本格式是最容易处理、最通用的格式
这就意味着尽量不要使用二进制数据进行通信,不要把二进制内容作为输出和输入。
4. 优化原则。 在功能实现之前,不要考虑对它优化。最重要的是让一切先能够运行,其次才是效率。

"先求运行,再求正确,最后求快。"(Make it run, then make it right, then make it fast.)
90%的功能现在能实现,比100%的功能永远实现不了强。先做出原型,然后找出哪些功能不必实现,那些不用写的代码显然无需优化。目前,最强大的优化工具恐怕是Delete键。

 

 

再来一个 CR和LF的八卦 《回车和换行

在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。
于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做"回车",告诉打字机把打印头定位在左边界;另一个叫做"换行",告诉打字机把纸向下移一行。
这就是"换行"和"回车"的来历,从它们的英语名字上也可以看出一二。

后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。

Unix系统里,每行结尾只有"<换行>",即"\n";

Windows系统里面,每行结尾是"<回车><换行>",即"\r\n";

Mac系统里,每行结尾是"<回车>"。

一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。

 

再来一个EOF的八卦(Link

 

EOF不是特殊字符,而是一个定义在头文件stdio.h的常量,一般等于-1。

  #define EOF (-1)

在Linux系统之中,EOF根本不是一个字符,而是当系统读取到文件结尾,所返回的一个信号值(也就是-1)。至于系统怎么知道文件的结尾,资料上说是通过比较文件的长度

所以,处理文件可以写成下面这样:

  int c;
  while ((c = fgetc(fp)) != EOF) {
    do something
  }

这样写有一个问题。fgetc()不仅是遇到文件结尾时返回EOF,而且当发生错误时,也会返回EOF。因此,C语言又提供了feof()函数,用来保证确实是到了文件结尾。上面的代码feof()版本的写法就是:

  int c;
  while (!feof(fp)) {
    c = fgetc(fp);
    do something;
  }

但是,这样写也有问题。fgetc()读取文件的最后一个字符以后,C语言的feof()函数依然返回0,表明没有到达文件结尾;只有当fgetc()向后再读取一个字符(即越过最后一个字符),feof()才会返回一个非零值,表示到达文件结尾。

所以,按照上面这样写法,如果一个文件含有n个字符,那么while循环的内部操作会运行n+1次。所以,最保险的写法是像下面这样:

  int c = fgetc(fp);
  while (c != EOF) {
    do something;

    c = fgetc(fp);
  }
  if (feof(fp)) {
    printf("\n End of file reached.");
  } else {
    printf("\n Something went wrong.");
  }

 

EOF还可以表示标准输入的结尾。

  int c;
  while ((c = getchar()) != EOF) {
    putchar(c);
  }

但是,标准输入与文件不一样,无法事先知道输入的长度,必须手动输入一个字符,表示到达EOF

 

Linux中,在新的一行的开头,按下Ctrl-D,就代表EOF(如果在一行的中间按下Ctrl-D,则表示输出"标准输入"的缓存区,所以这时必须按两次Ctrl-D);Windows中,Ctrl-Z表示EOF。(顺便提一句,Linux中按下Ctrl-Z,表示将该进程中断,在后台挂起,用fg命令可以重新切回到前台;按下Ctrl-C表示终止该进程。)

那么,如果真的想输入Ctrl-D怎么办?这时必须先按下Ctrl-V,然后就可以输入Ctrl-D,系统就不会认为这是EOF信号。Ctrl-V表示按"字面含义"解读下一个输入,要是想按"字面含义"输入Ctrl-V,连续输入两次就行了。

 

Unix目录结构的八卦(Link

Unix(包含Linux)的初学者,常常会很困惑,不明白目录结构的含义何在。

举例来说,根目录下面有一个子目录/bin,用于存放二进制程序。但是,/usr子目录下面还有/usr/bin,以及/usr/local/bin,也用于存放二进制程序;某些系统甚至还有/opt/bin。它们有何区别?

一般是根据《Unix文件系统结构标准》(Filesystem Hierarchy Standard),死记硬背不同目录的区别。

/bin : Essential user command binaries (for use by all users)

/boot : Static files of the boot loader

/dev : Device files

/etc : Host-specific system configuration

/home : User home directories (optional)

/lib : Essential shared libraries and kernel modules

/media : Mount point for removeable media

/mnt : Mount point for a temporarily mounted filesystem

/opt : Add-on application software packages

/root : Home directory for the root user (optional)

/sbin : System binaries

/srv : Data for services provided by this system

/tmp : tmp

 

Rob Landley的简短解释,原来Unix目录结构是历史造成的。

1969年,Ken ThompsonDennis Ritchie在小型机PDP-7上发明了Unix。1971年,他们将主机升级到了PDP-11。当时,他们使用一种叫做RK05的储存盘,一盘的容量大约是1.5MB。

没过多久,操作系统(根目录)变得越来越大,一块盘已经装不下了。于是,他们加上了第二盘RK05,并且规定第一块盘专门放系统程序,第二块盘专门放用户自己的程序,因此挂载的目录点取名为/usr。也就是说,根目录"/"挂载在第一块盘,"/usr"目录挂载在第二块盘。除此之外,两块盘的目录结构完全相同,第一块盘的目录(/bin, /sbin, /lib, /tmp...)都在/usr目录下重新出现一次。

后来,第二块盘也满了,他们只好又加了第三盘RK05,挂载的目录点取名为/home,并且规定/usr用于存放用户的程序,/home用于存放用户的数据。

 

从此,这种目录结构就延续了下来。随着硬盘容量越来越大,各个目录的含义进一步得到明确。

  /:存放系统程序,也就是At&t开发的Unix程序。

  /usr:存放Unix系统商(比如IBM和HP)开发的程序。

  /usr/local:存放用户自己安装的程序。

  /opt:在某些系统,用于存放第三方厂商开发的程序,所以取名为option,意为"选装"。

 

另外关于 /bin 和 /sbin 的区别 (Link

bin: 
bin为binary的简写 主要放置一些系统的必备执行档 例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar等。

/usr/bin:
主要放置一些应用软体工具的必备执行档 例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、 gzip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb*、wget等。 

/sbin: 
主要放置一些系统管理的必备程式 例如:cfdisk、dhcpcd、dump、e2fsck、fdisk、halt、ifconfig、ifup、 ifdown、init、insmod、lilo、lsmod、mke2fs、modprobe、quotacheck、reboot、rmmod、 runlevel、shutdown等。

/usr/sbin:

放置一些网路管理的必备程式例如:dhcpd、httpd、imap、in.*d、inetd、lpd、named、netconfig、nmbd、samba、sendmail、squid、swap、tcpd、tcpdump等

 

 

 

云主机

另一篇云主机的文章中(Link),我觉得下面这句比较有道理:

如果你想把钱藏在安全的地方,请问你是选择家中床垫下面,还是选择银行?这个比喻对服务器管理的方方面面都适用,不仅是安全性,还包括正常运行时间带宽负载管理备份等等,都是我们占优。

 

posted @ 2016-12-05 15:56  blcblc  阅读(409)  评论(0编辑  收藏  举报