The Linux Command Line@学习笔记

时间列表

  • Fri Jun 10 10:36:52 CST 2011
    • 第一章 至 第五章
  • Mon Jun 13 10:09:58 CST 2011
    • 第六章 至 第八章
  • Tue Jun 14 10:11:23 CST 2011
    • 第八章 至 第十一章
  • Wed Jun 15 10:35:08 CST 2011
    • 第十一章 至 第十五章
  • Mon Jun 20 11:15:03 CST 2011
    • 第十六章 至 第十八章
  • Tue Jun 21 15:56:38 CST 2011
    • 第十八章 至 第十九章
  • Mon Jun 27 11:02:19 CST 2011
    • 第十九章 至 第二十章
  • Tue Jun 28 23:03:21 CST 2011
    • 第二十章 至 第二十章
  • Thu Jun 30 16:39:12 CST 2011
    • 第二十章 至 第二十一章
  • Fri Jul 1 11:45:35 CST 2011
    • 第二十一章 至 第二十一章
  • Tue Jul 5 11:52:56 CST 2011
    • 第二十一章 至 第二十一章
  • Thu Jul 7 19:34:07 CST 2011
    • 第二十一章 至 第二十一章
  • Tue Jul 19 00:29:44 CST 2011
    • 第二十一章 至 第二十二章
  • Wed Jul 20 23:59:58 CST 2011
    • 第二十二章 至 第二十三章
  • Fri Jul 22 00:01:08 CST 2011
    • 第二十三章 至 第二十五章
  • Wed Jul 27 10:48:28 CST 2011
    • 第二十五章 至 第二十七章
  • Thu Jul 28 10:16:02 CST 2011
    • 第二十八章 至 第三十三章
  • Fri Jul 29 18:57:21 CST 2011
    • 第三十四章 至 第三十七章

Part 1 – Introduction

第一章

简介

首先进入gnome-terminal<终端>, 我的系统是ubuntu11.04, 终端是 bash

终端常用快捷键

在Linux下你可以有7个不同的终端. 这个命令的意思是:
    “同时按住<Ctrl>键和<Alt>键, 然后按<F1>键, 再释放所有的键”.

<Ctrl><Alt><Fn> (n=1..6) 切换到第n个文本终端.

打印出你正在使用的终端名称, 如果你希望知道终端的名字, 可以使用命令

ecos@ubuntu:~$ fgconsole

打开终端最简单的方法使用快捷键

Ctrl + Alt + T

ctrl-c和ctrl-z的区别
CTRL-C 和 CTRL-Z 都是中断命令, 但是他们的作用却不一样.

CTRL-C 是强制中断程序的执行
CTRL-Z 是停止任务并放入后台

用户可以使用 fg / bg 操作继续前台或后台的任务

jobs   - 显示当前暂停的进程
bg %N  - 使第N个任务在后台运行(%前有空格)
fg %N  - 使第N个任务在前台运行

默认 bg / fg 不带 %N 时表示对最后一个进程操作!
例如:
当你vim一个文件时, 如果需要用shell执行别的操作, 但是你又不打算关闭vim

你可以简单的按下CTRL-Z, shell会将vim进程挂起

当你结束了那个shell操作之后, 你可以用fg命令继续vim你的文件. 不是很方便么?!

其他快捷键

 # 结束前的进程. 按两次会退出终端.
ctrl + d

# 停止终端传输
ctrl + s

# 从新开始终端传输. 如果你的终端突然莫名其妙的停止响应, 可以参考上一条命令.
ctrl + q

# 恢复崩溃的终端(有些终端显示一些奇怪的字符)到缺省的设置.
# 当你使用cat命令准备显示一个二进制文件时, 你可能看不到你所输入的命令, 尽管命令仍然照常工作.
reset

# 粘贴当前选择的文本. 这是一个常规的Linux“复制-粘贴”操作.
<鼠标的中间键>

注释

ecos@ubuntu:~$ 命令 # ecos 表示当前用户的名字 ubuntu 表示计算机的名字

ecos@ubuntu:~$ exit # 退出终端

Part 2 – Learning The Shell

第二章

尝试一些简单得命令
date
cal
df
free

date

显示当前的时间和日期

ecos@ubuntu:~$ date
Fri Jun 10 10:44:29 CST 2011

cal

显示当前月的日历

ecos@ubuntu:~$ cal
     June 2011
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

df

查看磁盘驱动的类型使用情况

ecos@ubuntu:~$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             75924576  13764484  58303300  20% /
none                    502832       688    502144   1% /dev
none                    512068       704    511364   1% /dev/shm
none                    512068       116    511952   1% /var/run
none                    512068         0    512068   0% /var/lock
/home/ecos/.Private   75924576  13764484  58303300  20% /home/ecos

free

显示内存类型使用情况

ecos@ubuntu:~$ free
             total       used       free     shared    buffers     cached
Mem:       1024140     998164      25976          0       1884      89048
-/+ buffers/cache:     907232     116908
Swap:      1045500     257940     787560

第三章

首先我们要学会如何在linux系统下如何浏览文件, 在这一章中, 我们将介绍以下命令
pwd - 打印当前所在目录的名称
cd  - 改变目录
ls  - 打印目录的内容

pwd

ecos@ubuntu:~$ pwd
/data/svn/ecosdoc/source/misc

cd

改变目录, 绝对路径 / , / 代表根目录

ecos@ubuntu:~$ cd /

ecos@ubuntu:~$ ls
bin
boot
cdrom
data
dev
etc
home
initrd.img
lib
lost+found
media
mnt
opt
proc
root
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
进入当前用户的主目录有两种方法
ecos@ubuntu:~$ cd /home/ecos/
另一种方法
ecos@ubuntu:~$ cd ~
也就是~代表当前用户主目录, 明白了吧. 比如我们要进入主目录的Doucments文件夹直接可以
ecos@ubuntu:~$ cd ~/Documents
这里要说一下, 在linux文件系统里面对文件和文件夹的名字有严格的限制, 区分大小写. 多多注意.

ls

我们要知道当前目录里面的文件夹和文件我们用 ls 命令

ecos@ubuntu:~$ ls
Desktop Documents Music Pictures Public Templates Videos

第四章

现在,我们知道了如何移动文件系统,
稍后,我带领大家参观我们的Linux系统.
然而,在我们开始前我们要学习一些指令,沿途会有用的.
ls    - 打印目录的内容
file  - 打印文件类型
less  - 显示文本文件的内容

ls

ls 有一些我们常用的参数, 比如我们要知道当前目录的所有内容, 包括隐藏文件夹和文件和所有属性, 例

ecos@ubuntu:~$ ls -al
drwxrwxr-x  2 ecos ecos  4096 2011-06-05 01:43 Ubuntu One
drwxr-xr-x  5 ecos ecos  4096 2011-06-05 17:14 Videos
drwxr-xr-x 19 ecos ecos  4096 2011-06-06 19:33 .vim
-rw-------  1 ecos ecos 25033 2011-06-10 09:41 .viminfo
-rw-r--r--  1 ecos ecos 16264 2011-06-08 20:48 .vimrc
drwxr-xr-x  2 ecos ecos  4096 2011-06-06 16:37 .VirtualBox
drwxr-xr-x  3 ecos ecos  4096 2011-06-06 16:40 VirtualBox VMs

file

确定一个文件什么文件类型我们用 file, 使用方法如下

ecos@ubuntu:~$ file linuxcommand.t2t
linuxcommand.t2t: UTF-8 Unicode English text

ecos@ubuntu:~$ file Tsung.jpg
Tsung.jpg: JPEG image data, JFIF standard 1.02

less

less 打印文本文件内容

ecos@ubuntu:~$ less /etc/passwd
进入之后我们可以用快捷键控制
Command Action
Page Up or b Scroll back one page
Page Down or space Scroll forward one page
Up Arrow Scroll up one line – Exploring The System
Down Arrow Scroll down one line
G Move to the end of the text file
1G or g Move to the beginning of the text file
/characters Search forward to the next occurrence of characters
n Search for the next occurrence of the previous search
h Display help screen
q Quit less

less is more

程序设计less为了一个更早的一种改进的更换系统项目叫做more.

命名为“少”是一个玩这个短语“少即是多”
                    ——一种现代主义建筑师和设计师的座右铭.

便于用户浏览的长文本文件在一页一页的态度. 而更多的程序只能向前,减少页面分页两计划允许向前和向后,还有许多其它的优点.

第五章

对文件的各种操作
在这一点上我们准备一些真正的工作, 本章将介绍下面几个命令
cp     - 复制
mv     - 移动或重命名
mkdir  - 创建一个目录
rm     - 删除
ln     - 创建一个应链接或符号链接
这五个命令是最为常用的Linux命令. 他们是用于操纵文件和目录.

坦率地说,现在好多人都是通过图形界面,我们可以通过拖放一个文件 从一个目录移到另一个、剪切和粘贴文件,删除文件,等等.
为什么要使用这些旧命令行的方式?

答案是力量和灵活性. 当它简便易行,简单的文件操作提供图形文件管理器,可以更复杂的任务的命令行程序.

例如,我们如何能复制所有的HTML文件从一个目录复制到另一个目录, 在目标目录只拷贝不存在的文件,或者更新现有的相应的文件.
一个有经验的linux档案管理员. 很容易该命令行:
cp -u *.html 目标目录

通配符(Wildcards)

在开始使用命令之前,我们需要谈一谈shell的特点,使这些命令强大.  因为shell使用文件名太多,它提供了特别的指定的角色来帮助你很快的
操作群体的文件名. 这些特别的角色操纵的文件和目录称为通配符. 使用通配字符(也被称为globbing)允许你选择基于模式的文件名字符.

下表列出了通配符:
Wildcard Meaning
* 匹配所有
? 匹配一个
[characters] Matches any character that is a member of the set characters
[!characters] Matches any character that is not a member of the set characters
[[:class:]] Matches any character that is a member of the specified class

字符类匹配

Character Class Meaning
[:alnum:] Matches any alphanumeric character
[:alpha:] Matches any alphabetic character
[:digit:] Matches any numeral
[:lower:] Matches any lowercase letter
[:upper:] Matches any uppercase letter

例子

Pattern Matches
* 所有文件
g* 所有以“g”开头的文件
b*.txt 所有以“b”开头并以“.txt”结尾的文件
Data??? 以“Data”开头并且后面有任意三个字符的文件
[abc]* 匹配所有以“a”, “b”, “c”开头的文件
BACKUP.[0-9][0-9][0-9] 匹配“BACKUP.”后面是三个0-9整数的文件
[[:upper:]]* 所有以大写字母开头的文件
[![:digit:]]* 所有没有字母开头的文件
*[[:lower:]123] 所有以任何小写字母开头并且以“1”, “2”, “3”结尾的文件

可以使用通配符,接受任何命令的文件名作为参数,但我们会谈论更多关于在第八章.

cp

复制文件/目录

ecos@ubuntu:~$ cp item1 item2    # 把item复制到directory目录

ecos@ubuntu:~$ cp item... directory
常用参数
Option Meaning
-a 档案复制文件和目录和他们所有的属性,包括所有制共同和许可. 通常情况下,副本将用户的默认的属性进行复制.
-i 交互式改写,如果有这个文件,提示用户确认. 如果这个方案是没有具体规定,cp会静静地覆盖文件.
-r 递归复制目录和递归的内容. 这个选项(-a)时需要复制目录.
-u 更新,当复制文件从一个目录到另一个,要么,只拷贝不存在的文件,或者更新现有的相应的文件,在目的目录.
-v 显示信息进行复制

例子

ecos@ubuntu:~$ cp file1 file2    # 复制file1到file2

ecos@ubuntu:~$ cp -i file1 file2 # 复制过程中如果有这个文件提示是否覆盖

ecos@ubuntu:~$ cp dir1/* dir2    # 复制目录下所有文件或目录到目标目录

ecos@ubuntu:~$ cp -r dir1 dir2   # 递归复制

mkdir

创建目录

参数

Option Meaning
-p 递归创建

ecos@ubuntu:~$ mkdir dir

ecos@ubuntu:~$ mkdir dir1 dir2 dir3      # 创建多个文件夹

ecos@ubuntu:~$ mkdir -p /dir1/dir2/dir3  # 递归创建文件夹

mv

移动文件/文件夹
也用于重命名

常用参数

Option Meaning
-i 覆盖现有的一个文件之前,提示用户确认. 如果这个方案是没有具体规定,mv默认覆盖文件
-u 更新,当复制文件从一个目录到另一个,要么,只拷贝不存在的文件,或者更新现有的相应的文件,在目的目录.
-v 显示信息

例子

ecos@ubuntu:~$ mv file1 file2      # 重命名

ecos@ubuntu:~$ mv -i file1 file2   # 如果存在提示是否写入

ecos@ubuntu:~$ mv file1 file2 dir1 # 移动 file1 file2 至 dir1

ecos@ubuntu:~$ mv dir1 dir2        # 移动 dir1 至 dir2

rm

删除(delete)文件/文件夹

参数

Option Meaning
-r 删除文件夹, 递归删除
-f 强制删除

例子

ecos@ubuntu:~$ rm file1

ecos@ubuntu:~$ rm file1 dir1

ecos@ubuntu:~$ rm -r dir1

ecos@ubuntu:~$ rm -rf dir1

ln

链接

参数

Option Meaning
-s 符号链接链接

例子

ecos@ubuntu:~$ ln file1 dir/        # 创建硬链接

ecos@ubuntu:~$ ln -sv file2 dir/    # 符号链接不会占用硬盘空间, 但是源没有了就什么都没有了
`dir/file2' -> `file2'

第六章

到目前为止,我们已经看到一系列神秘的命令,每一个都有自己的神秘的选项和参数.
在这一章中,我们将努力去除一些的这奥秘. 这一章我们将介绍
type    - 解读一个命令
which   - 显示哪些是可执行程序
man     - 显示命令手册
apropos - 显示一个合适的命令列表
info    - 显示一个命令信息
whatis  - 显示非常简短的描述一个命令
alias   - 为命令创建一个别名

例子

# type
ecos@ubuntu:~$ type type
type is a shell builtin

ecos@ubuntu:~$ type ls
ls is /bin/ls

ecos@ubuntu:~$ type cp
cp is /bin/cp

# which 确定一个可执行程序的位置
ecos@ubuntu:~$ which ls
/bin/ls

ecos@ubuntu:~$ which vim
/usr/bin/vim

help

获得帮助信息, 在每个shell命令的后面加上--help参数, 如
ecos@ubuntu:~$ ls --help
...

man

获得命令指南

用法

man program
man section search_term
例子
ecos@ubuntu:~$ man ls
...
ecos@ubuntu:~$ man 5 passwd
...

apropos

恰当的显示合适额命令,这是一个搜索为man而被创造

例子

ecos@ubuntu:~$ apropos floppy
fdformat (8)         - Low-level formats a floppy disk
make-memtest86+-boot-floppy (1) - create a memtest86+ boot-floppy using GRUB.
mbadblocks (1)       - tests a floppy disk, and marks the bad blocks in the FAT
mformat (1)          - add an MSDOS filesystem to a low-level formatted floppy disk
mxtar (1)            - Wrapper for using GNU tar directrly from a floppy disk

whatis

显示一个简短的描述

例子

ecos@ubuntu:~$ whatis ls
ls (1)               - list directory contents

ecos@ubuntu:~$ whatis vim
vim (1)              - Vi IMproved, a programmers text editor

info

信息页显示为读者程序命名,适当的不够,信息.
信息页是超链的很像的网页.
命令 行动
? 显示命令的帮助
PgUp or Backspace 显示前一页
PgDn or Space 显示下一页
n next, 显示下一个节点
p previous, 显示前一个节点
u up, 显示当前节点的父节点,通常是一个菜单
Enter 超链接进入遵循游标目前的位置
q 退出

例子

ecos@ubuntu:~$ info coreutils
...

alias

创建自己的命令

例子

ecos@ubuntu:~$ type test
test is a shell builtin

ecos@ubuntu:~$ type foo
/bin/bash: line 0: type: foo: not found      # 什么都没有

ecos@ubuntu:~$ alias foo='cd /usr; ls; cd -'

ecos@ubuntu:~$ alias name='string'

ecos@ubuntu:~$ alias                         # 创建de自定义命令都打印出来
alias foo='cd /usr; ls; cd -'
alias name='string'

ecos@ubuntu:~$ foo
bin include lib local man sbin share src
/home/ecos

ecos@ubuntu:~$ type foo
foo is aliased to 'cd /usr; ls; cd -'

ecos@ubuntu:~$ unalias foo                   # 销毁foo

ecos@ubuntu:~$ alias                         # 只剩下name了
alia name='string'

ecos@ubuntu:~$ type foo                      # 什么都没有
/bin/bash: foo: command not found

ecos@ubuntu:~$ unalias name                  # 销毁name

第七章

在这节课我们将释放可能是最酷的特征的命令线.
它叫I / O重定向. “I / O”代表输入/输出和这个设备你能重新传入输入和输出指令和文件,
以及连接在强大的操作指令命令管道. 炫耀这设备, 我们将介绍以下命令:
cat  - 连结档案
sort - 排序行文本的分类
uniq - 报告或省略重复线
grep - 打印符合匹配模式部分
wc   - 打印印换行符、文字、和二进制数为每个文件
head - 输出文件的第一部分
tail - 输出文件的最后一部分
tee  - 读取标准输入和标准输出和写文件

我们先来看几个例子

1.

ecos@ubuntu:~$ ls                                  # ls 看到有2个文件
file1.txt file2.txt

ecos@ubuntu:~$ cat file1.txt                       # file1什么都没有, 是个空文件

ecos@ubuntu:~$ cat > file1.txt                     # 输入内容
a
b
c
(ctrl+d结束输入)

ecos@ubuntu:~$ cat file1.txt                       # 看看有没有(肯定有了- -)
a
b
c
ecos@ubuntu:~$
file1写好内容以后我们继续

2.

ecos@ubuntu:~$ cat file2.txt
aa
bb
cc
ecos@ubuntu:~$                                     # file2里面有东西的

ecos@ubuntu:~$ cat file1.txt >> file2.txt          # 把file1里面的东西加到file2的里面

ecos@ubuntu:~$ cat file2.txt
aa
bb
cc
a
b
c
ecos@ubuntu:~$                                     # 添加成功

ecos@ubuntu:~$ cat file1.txt file2.txt > file3.txt # 把file1和file2中的内容都添加到file3中去

ecos@ubuntu:~$ cat file3.txt
aa
bb
cc
a
b
c
ecos@ubuntu:~$
明白这些下面就容易理解了

3.

ecos@ubuntu:~$ ls
file1.txt file2.txt file3.txt

ecos@ubuntu:~$ ls > ls.txt

ecos@ubuntu:~$ cat ls.txt
file1.txt file2.txt file3.txt ls.txt

4. 实用的例子

# 写入硬件信息:
ecos@ubuntu:~$ dmesg | cat > dmesg.txt

# 写入cup信息:
ecos@ubuntu:~$ cat /proc/cpuinfo > cpu.txt

# 写入内存信息:
ecos@ubuntu:~$ cat /proc/meminfo > meminfo.txt

# 还有很多很多
# 查看USB设备:cat /proc/bus/usb/devices
# 查看键盘和鼠标:cat /proc/bus/input/devices
# 查看系统硬盘信息和使用情况:fdisk -l & df -h
# 查看硬盘读写速度 hdparm -tT /dev/sda
# 查看各设备的中断请求(IRQ):cat /proc/interrupts
# 查看系统体系结构:uname -a
...

cat

可以链接一个或者多个文件

例子

ecos@ubuntu:~$ cat file1
aaa

ecos@ubuntu:~$ cat file2
bbb

ecos@ubuntu:~$ cat file1 file2
aaa
bbb

Pipelines

管道
命令的能力从标准输入读取数据,发送到标准输出
利用壳功能叫做管道. 使用管道操作”|”(垂直杆)
标准输出一条指令可以标准输入管道连接到另一个:

语法

command1 | command2
例子
# 其实上面的例子中已经用到过了
ecos@ubuntu:~$ dmesg | cat > dmesg.txt

ecos@ubuntu:~$ ls / | sort | uniq | wc -l
23

ecos@ubuntu:~$ ls /bin /usr/bin | sort | uniq
[
2to3
2to3-2.7
411toppm
7z
7za
a2p
aclocal
...
zless
zmore
znew
zsoelim

grep

grep是一个功能强大的程序来找到文本模式在文件. 它的使用这样的:
grep pattern [file...]

例子

ecos@ubuntu:~$ ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
bzip2recover
funzip
gpg-zip
gunzip
gzip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
grep是使用率非常高的一个命令, 最多的实在做查询条件出现, 作用相当与过滤.(我个人观点)

head / tail

Print First / Last Part Of Files

例子

ecos@ubuntu:~$ head -n 5 cpuinfo.txt
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 13
model name	: Intel(R) Pentium(R) M processor 2.00GHz

ecos@ubuntu:~$ tail -n 5 cpuinfo.txt
clflush size	: 64
cache_alignment	: 64
address sizes	: 32 bits physical, 32 bits virtual
power management:

ecos@ubuntu:~$ ls /usr/bin | head -n 5
[
2to3
2to3-2.7
411toppm
7z

ecos@ubuntu:~$ ls /usr/bin | tail -n 5
zipinfo
zipnote
zipsplit
zjsdecode
zsoelim

tee

标准输入与输出文件

例子

ecos@ubuntu:~$ tee haha
ads
addasd
das
(ctrl+d 结束输入)

ecos@ubuntu:~$ cat haha
ads
addasd
das

ecos@ubuntu:~$

第八章

这一章中, 我们介绍几个有趣的有复杂特性的命令
echo      - 显示一行文本

例子

ecos@ubuntu:~$ echo this is a test
this is a test

ecos@ubuntu:~$ echo *
Desktop Documents Music Pictures Public Templates  Videos

ecos@ubuntu:~$ echo D*
Desktop Documents

ecos@ubuntu:~$ echo *s
Documents Pictures Templates Videos

ecos@ubuntu:~$ echo [[:upper:]]*
Desktop Documents Music Pictures Public Templates  Videos

ecos@ubuntu:~$ echo /usr/*/share
/usr/kerberos/share /usr/local/share

算数扩展用法

$((expression))

运算符

Operator Description
+ 加法
- 减法
* 乘法
/ 除法
% 取模
** 求幂

例子

ecos@ubuntu:~$ echo $((2+2))
4

ecos@ubuntu:~$ echo $(($((5**2))*3))
75

ecos@ubuntu:~$ echo Five divided by two equals $((5/2))
Five divided by two equals 2

ecos@ubuntu:~$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back

ecos@ubuntu:~$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5

ecos@ubuntu:~$ echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

ecos@ubuntu:~$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b
所以这有什么好处呢?最常见的应用就是让列出的文件或者目录被创造出来.

同时创建有规则文件夹

例如, 如果我们有一个很大的摄影师采集的图像,我们想要组织年又一个月,我们首先可以做的是创建一个系列的目录Year-Month命名为“数字”格式.这目录名称,按时间顺序将排序. 我们可以打一份完整的目录清单,但是那是一个许多工作是容易出错了. 相反,我们可以做这个:

ecos@ubuntu:~$ mkdir Pics
ecos@ubuntu:~$ Pics
ecos@ubuntu:~$ cd Pics
ecos@ubuntu:~$ mkdir {2011..2012}-0{1..9} {2011..2012}-{10..12}
ecos@ubuntu:~$ ls
2011-01  2011-03  2011-05  2011-07  2011-09  2011-11  2012-01  2012-03  2012-05  2012-07  2012-09  2012-11
2011-02  2011-04  2011-06  2011-08  2011-10  2011-12  2012-02  2012-04  2012-06  2012-08  2012-10  2012-12
再看这个例子
ecos@ubuntu:~$ echo $(ls)
Desktop Documents Music Pictures Public Templates Videos

ecos@ubuntu:~$ ls -l $(which cp)
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp

ecos@ubuntu:~$ file $(ls /usr/bin/* | grep zip)
/usr/bin/funzip:     ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
/usr/bin/gpg-zip:    POSIX shell script text executable
/usr/bin/mzip:       symbolic link to `mtools'
/usr/bin/preunzip:   POSIX shell script text executable
/usr/bin/prezip:     POSIX shell script text executable
/usr/bin/prezip-bin: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
...

ecos@ubuntu:~$ ls -l $(which cp)
-rwxr-xr-x 1 root root 100220 2011-02-23 21:22 /bin/cp

单引号和双引号

现在我们已经看到了许多例子,我们用点时间学习如何能正确使用它的扩展. 举例来说:
1.
ecos@ubuntu:~$ echo this is a           test
this is a test

ecos@ubuntu:~$ echo "this is a           test" # 两个的区别看清楚没
this is a         test

2.
ecos@ubuntu:~$ echo The total is $100.00
The total is 00.00                             # 这里输出00.00是因为 $100.00 是未定意变量

ecos@ubuntu:~$ echo The total is \$100.00
The total is $100.00                           # 逃脱以后就好了

3.
ecos@ubuntu:~$ echo "$USER $((2+2)) $(cal)"
ecos 4      June 2011
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

ecos@ubuntu:~$ echo $(cal)
June 2011 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

ecos@ubuntu:~$ echo "$(cal)"
     June 2011
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

4.
ecos@ubuntu:~$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/ecos/*.txt a b foo 4 ecos

ecos@ubuntu:~$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 ecos

ecos@ubuntu:~$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
正确使用引号可以帮助我们完成不同的需求

字符逃脱

如下表

Escape Sequence Meaning
\a Bell (“Alert” - causes the computer to beep)
\b Backspace
\n 换行
\r 回车
\t Tab

例子

ecos@ubuntu:~$ sleep 10; echo -e "Time's up\a"
Time's up

ecos@ubuntu:~$ sleep 10; echo "Time's up" $'\a'
Time's up

第九章

我们需要做大部分的工作最少的敲击按键. 另一个愿望是永远不必提起你的手指控制键盘,从不用鼠标.
在这一章,我们将看看敲击键盘使用特点,使我们更快和更有效率.

下列命令将使一个外观:

clear       - 清除屏幕
history     - 显示内容的历史列表

控制光标

Key Action
Ctrl-a 移动到行首
Ctrl-e 移动到行尾
Ctrl-f 向右移动一个字符
Ctrl-b 向左移动一个字符
Alt-f 光标向前移动一个单词
Alt-b 光标向后移动一个单词
Ctrl-l 清屏, 作用和clear一样

文本控制

Key Action
Ctrl-d 删除字符到光标的位置
Ctrl-t 调换光标前一个字符
Alt-t 调换光标前一个单词
Alt-l 从光标位置开始转换成小写字母
Alt-u 从光标位置开始转换成大写字母

剪切和粘贴

Key Action
Ctrl-k 从光标位置删除到行尾
Ctrl-u 从光标位置删除到行首
Alt-d 从光标位置删除一个单词
Alt-Backspace 从光标位置删除前一个字符
Ctrl-y 从kill-ring拽Ctrl-y文本,把它插入游标目前的位置

自动提示

Key Action
Alt - ? 显示列表可能的完满. 你也可以在大多数系统上, 这样按tab键可以一次,这是容易得多
Alt - * 插入所有可能的完满. 这是有益的,当你想要使用不只一个可能的匹配

那里有一些会发现默默无闻的. 你可以看到一个列表,“READLINE”.

history

历史记录

一些例子

ecos@ubuntu:~$ history | grep /usr/bin
...
88 ls
...

ecos@ubuntu:~$ !88
ls
Desktop Documents Music Pictures Public Templates Videos

History Commands

Key Action
Ctrl-p 跳转到上一个历史动作
Ctrl-n 跳转到下一个历史动作
Alt - < 搬到开始(top)的历史列表
Alt - > 移动到结束(bottom)的历史列表,即当前命令行
Ctrl-r 反向增量搜索. 从目前搜索命令行不断的历史列表
Alt-p 反向搜索,non-incremental. 这把钥匙,在搜索字符串类型,按回车键在搜索被执行
Alt-n 搜索,non-incremental了.
Ctrl-o 完成当前的项目清单和历史前进到下一个. 这是方便的,如果你正试图re-execute一系列命令,历史列表

History Expansion

Sequence Action
!! 重复最后的命令
!number 重复历史列表对应的号码
!string 重复历史列表项中开始字符串的历史
!?string 重复历史列表项包含字符串的历史

我们要注意使用“!sting”和“!?srting”, 除非你绝对确定历史内容的列表条目.

script

除了要掌握history,大多数历史功能的Linux包括一个项目叫做脚本可以用来记录整个
shell session, 存储在一个文件中. 的基本语法的命令是:
script [file]

第十章

权限
id     - 显示用户的身份
chmod  - 改变一个文件的模式
umask  - 指定在建立文件时预设的权限掩码
su     - shell作为另一个用户
sudo   - 用另一个用户执行一个命令
chown  - 改变一个文件的所有者
chgrp  - 改变一个文件的所有权
passwd - 改变用户的密码

例子

ecos@ubuntu:~$ file /etc/shadow
/etc/shadow: regular file, no read permission

ecos@ubuntu:~$ id
uid=1000(ecos) gid=1000(ecos) groups=1000(ecos),4(adm),20(dialout),24(cdrom),46(plugdev),112(lpadmin),120(admin),122(sambashare)

File Types

Attribute File Type
- 文件
d 目录
l 链接符号. 注意,而用符号链接,剩下的文件总是rwxrwxrwx属性”,都是虚构的. 真正的文件属性是这个符号链接指向档案
c 一个角色特别的文件. 这个文件类型是指一种装置,它处理数据作为一个流的字节,如终端或调制解调器
b 一块特别的文件. 这个文件类型是指一种装置, 如一个硬盘或cd - rom驱动
剩下的9个字符的文件属性,叫做文件模式,代表着
读、写、执行权限的文件的主人,这个文件的所有者
Owner Group World
rwx rwx rwx

权限属性

属性 文件 目录
r 允许文件被打开阅读 允许一个目录的内容显示如果执行属性也设置
w 允许文件写入,然而这个属性不允许文件改名或删除. 能够删除或重命名文件是由目录的属性 允许文件在一个目录被创造,删除,并重新命名为“如果执行属性也设置
x 允许文件将其视为一个程序和执行. 程序文件写在脚本语言也必须设置为可读可执行 允许一个目录进入,例如,cd目录
我们使用和八进制批注八进制数字来设置模式目的的权限.
由于每一位在一个八进制数字代表三个二进制数字,如图
Octal Binary File Mode
0 000 ---
1 001 --x
2 010 -w-
3 011 -wx
4 100 r--
5 101 r-x
6 110 rw-
7 111 rwx

常用的
7 (rwx), 6 (rw-), 5 (r-x), 4 (r--), and 0 (---)

chmod

语法

chown [owner][:[group]] file...

chmod Symbolic Notation

Symbol Meaning
u Short for “use,r” but means the file or directory owner.
g Group owner.
o Short for “others,” but means world.
a Short for “all.” The combination of “u”, “g”, and “o”.

chmod Symbolic Notation Examples

Notation Meaning
u+x 添加所有人的执行许可
u-x 删除所有人的执行许可
+x 增加执行权限,相当与 a+x
o-rw 删除读和写的权限除了所有人和组所有者
go=rw 设置组所有者和任何人除了所有人有读和写权限. 如果一组所有者或世界的执行权限,他们此前已被取消
u+x,go=rx 加允许所有者和组织设置权限和其他人读和执行. 多种规格可以之间用逗号分隔

Here are some examples of using chmod with symbolic notation to set these
special permissions. First assigning setuid to a program:
chmod u+s program
Next, assigning setgid to a directory:
chmod g+s dir
Finally, assigning the sticky bit to a directory:
chmod +t dir
When viewing the output from ls, you can determine the special permissions.
Here are some examples. First, a program that is setuid:
-rwsr-xr-x

A directory that has the setgid attribute:

drwxrwsr-x
A directory with the sticky bit set:
drwxrwxrwt

umask

当前日期: 2011-06-30 星期四

umask命令是用来修改新建目录/文件的默认权限的.

对于文件来说, umask各位上的数字的最大值是 6, 因为系统不允许在创建一个文件时就赋予它执行权限, 所以必须在创建后用chmod命令
增加这一权限. 而目录则允许设置执行权限, 这样针对目录来说, umask中各个数字最大可以到7. 所以在linux下, 新建目录、文件的默认
权限分别是777、666; 而umask的默认值一般是022(不确定的话可以用umask命令查询), 所以, 新建一个文件夹/文件后, 此文件夹/文件
的初始权限为755/644.

运行umask命令只对于当前shell环境起作用, 当退出该shell便恢复到系统默认的缺省权限.

如果想每次登录后都使用自己设置的缺省权限, 将umask值添加到自己的home目录下的profile文件中即可.
如果希望永久地改变所有用户的umask值, 则要修改/etc/profile文件

权限掩码- umask

umask是chmod配套的, 总共为4位(gid/uid,属主, 组权, 其它用户的权限), 不过通常用到的是后3个, 例如你用chmod 755 file(此时这
文件的权限是属主读(4)+写(2)+执行(1),同组的和其它用户有读写权限)

umask值与权限

umask 文件 目录
0 6 7
1 6 6
2 4 5
3 4 4
4 2 3
5 2 2
6 0 1
7 0 0

常用的umask值及对应的文件和目录权限

umask值 目录 文件
022 755 644
027 750 640
002 755 664
006 771 660
007 770 660

umask的作用
默认情况下的umask值是022(可以用umask命令查看), 此时你建立的文件默认权限是644, 建立的目录的默认权限是755, 可以用ls -l验证一下哦.  

查看方式有两种, 一种是直接输入umask, 可以看到数字类型的权限设置分数, 另一种是加入 -S(Symbolic)参数, 就会以符号类型的方式显示权限.

在默认的情况中, root的umask会去掉比较多的属性, root的umask默认是022, 这是基于安全的考虑. 一般身份用户通常的umask为002, 即保留同用户
组的写入权力. 其实, 关于默认umask的设置可以参考 /etc/bashrc文件的内容, 不过, 建议不要修改该文件, 可以参考第11章提到的环境参数设置文件
(~/.bashrc)的说明.

Changing Identities

在不同的时期,我们会发现有必要接受另一个用户的身份. 经常我们要赢得超级使用者特权进行了一些行政任务,
但它也是可能”变成“另一个一般的使用者对诸如测试一个帐户. 有有三种方式去另一个身份.
    1. 登陆的用户.
    2. su
    3. sudo

su

切换用户

语法

su [-[l]] [user]
奇怪的缩写, '-l'可以缩写成'-', 成为超级用户
例子
ecos@ubuntu:~$ su -
Password:
root@ubuntu:~$
root@ubuntu:~$ exit
ecos@ubuntu:~$
可以用su单独执行一条命令
su -c 'command'
ecos@ubuntu:~$ su -v 'ls -l /root/*'
Password:
-rw------- 1 root root
754 2007-08-11 03:19 /root/anaconda-ks.cfg
/root/Mail:
total 0
ecos@ubuntu:~$

sudo

切换到超级用户权限
它会做这样的:
sudo vim /data/www/default/index.php
Password:
...

ecos@ubuntu:~$ sudo -l
Matching Defaults entries for ecos on this host:
    env_reset

User ecos may run the following commands on this host:
    (ALL) ALL

passwd

Changing Your Password

passwd [user]
ecos@ubuntu:~$ passwd
(current) UNIX password:
New UNIX password:
还有一些相关的命令
adduser
useradd
groupadd

第十一章

现代操作系统通常是多任务,这意味着他们所做的一件事立刻被一个执行程序快速切换到另一个地方.
Linux内核的管理这个通过使用过程. 过程是如何组织不同的程序Linux等待轮到自己在CPU. 有时一个计算机将变得缓慢或申请将停止响应.
在这一章中,我们将会看到一些工具,在指令行,让我们仔细检查程序所做的事情,以及如何终止过程.
本章将介绍以下命令:
ps         - 显示进程
top        - 任务列表
jobs       - 显示后台任务
bg         - 放到后台的任务
fg         - 继续后台中的任务
kill       - 杀死一个进程
killall    - 杀死所有进程
shutdown   - 关机
进程是神马
当一个系统启动时,内核启动一个它的几种自己的活动的过程, 启动一个项目叫做init. 初始运行, 反过来,
一系列的shell(etc)的初始脚本,所有的系统开始服务. 许多这些服务守护程序,程序实现的,只是坐在他们
的背景和做没有任何东西的用户界面. 所以,即使我们没有登录,该系统至少有一点忙执行常规的东西. 事实
上,一个程序可以推出其他程序表现在工艺方案一个父进程生小孩的过程.

ps

最常用的命令来查看进程(ps)是有好几个. ps程序有许多选项,但在它最简单的形式是使用这样的:

ecos@ubuntu:~$ ps
  PID TTY          TIME CMD
12562 ?        00:00:00 bash
12563 ?        00:00:00 ps

ecos@ubuntu:~$ ps x
  PID TTY      STAT   TIME COMMAND
13026 ?        Ss     0:00 /bin/bash -c (ps x) < /tmp/vnzS6PR/9 >/tmp/vnzS6PR/10 2>&1
13027 ?        R      0:00 ps x

ecos@ubuntu:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
ecos 13108  0.0  0.1   6624  1160 ?        Ss   18:48   0:00 /bin/bash -c (ps aux) < /tmp/vnzS6PR/11 >/tmp/vnzS6PR/12 2>&1
ecos 13109  0.0  0.1   4708  1164 ?        R    18:48   0:00 ps aux

top

看到一个更有活力的观点的机器的活动中,我们使用top命令:
ecos@ubuntu:~$ top
...

xlogo

现在我们可以看到和监控过程,让我们获得一些控制他们. 为我们的实验中,我们将用一个小项目叫做xlogo作为我们的检测法.
xlogo的程序是一个简单的程序提供X视窗系统(潜在的引擎,使我们的展示的图片显示的是一个简单的去re-sizable窗口包含X的
标志. 首先,我们将会知道我们的测试题目:
ecos@ubuntu:~$ xlogo                        # 运行这条命令后弹出一个X的窗口
^C                                          # ctrl+c 结束任务

ecos@ubuntu:~$ xlogo &                      # 在后台运行中
[1] 3583

ecos@ubuntu:~$ jobs                         # 查看后台停止的任务
[1]+ Running                  xlogo &

ecos@ubuntu:~$ fg 1                         # 前台运行
xlogo
^Z                                          # ctl+z
[1]+  Stopped                 xlogo         # 停止任务放到后台

ecos@ubuntu:~$ bg 1                         # 后台运行
[1]+ xlogo &

ecos@ubuntu:~$ jobs                         # 有了吧
[1]+  Running                 xlogo &

ecos@ubuntu:~$ ps                           # 查看进程
  PID TTY          TIME CMD
 4270 ?        00:00:00 bash
 3583 ?        00:00:00 xlogo
 4271 ?        00:00:00 ps

ecos@ubuntu:~$ kill 3583                    # 干掉xlogo
[1]+  Terminated              xlogo

ecos@ubuntu:~$ ps                           # 检查下, 没有了
  PID TTY          TIME CMD
 4270 ?        00:00:00 bash
 4271 ?        00:00:00 ps
ecos@ubuntu:~$ jobs                         # 看看后台的任务
ecos@ubuntu:~$                              # 什么都没有

Part 3 – Configuration And The Environment

第十二章

环境

在这一章中,我们将与下列命令:
printenv        - 打印部分或者所有的环境
set             - 设置shell选项
export          - 随后的执行程序退出环境
alias           - 给一条命令创建一个别名

例子

ecos@ubuntu:~$ printenv USER
ecos

ecos@ubuntu:~$ set | less
...

ecos@ubuntu:~$ echo $HOME
/home/ecos

ecos@ubuntu:~$ alias
alias vi='vim'
环境变量
DISPLAY EDITOR SHELL HOME LANG OLD_PWD PAGER PATH PS1 PWD TERM TZ USER

环境配置文件

FIle Contents
/etc/profile A global configuration script that applies to all users.
~/.bash_profile A user's personal startup file. Can be used to extend or override settings in the global configuration script.
~/.bash_login If ~/.bash_profile is not found, bash attempts to read this script.
~/.profile If neither ~/.bash_profile nor ~/.bash_login is found, bash attempts to read this file. This is the default in Debian-based distributions, such as Ubuntu.

Non-login shell sessions read the following startup files:

File Contents
/etc/bash.bashrc A global configuration script that applies to all users.
~/.bashrc A user's personal startup file. Can be used to extend or override settings in the global configuration script.

第十三章

vim

vi / vim
详细教程参照VIM Hacks

第十四章

颜色代码

Escape Sequences Used To Set Text Colors

Sequence Text Color Sequence Text Color
\033[0;30m Black \033[1;30m Dark Gray
\033[0;31m Red \033[1;31m Light Red
\033[0;32m Green \033[1;32m Light Green
\033[0;33m Brown \033[1;33m Yellow
\033[0;34m Blue \033[1;34m Light Blue
\033[0;35m Purple \033[1;35m Light Purple
\033[0;36m Cyan \033[1;36m Light Cyan
\033[0;37m Light Grey \033[1;37m White

例子

ecos@ubuntu:~$ PS1="\[\033[0;31m\]<\u@\h \W>\$ "
ecos@ubuntu:~$                                                      # 是不是很神奇

ecos@ubuntu:~$ PS1="\[\033[0;31m\]<\u@\h \W>\$\[\033[0m\] "
ecos@ubuntu:~$                                                      # 神奇不

Escape Sequences Used To Set Background Color

Sequence Background Color Sequence Background Color
\033[0;40m Black \033[0;44m Blue
\033[0;41m Red \033[0;45m Purple
\033[0;42m Green \033[0;46m Cyan
\033[0;43m Brown \033[0;47m Light Grey

例子

ecos@ubuntu:~$ PS1="\[\033[0;41m\]<\u@\h \W>\$\[\033[0m\] "
ecos@ubuntu:~$

Cursor Movement Escape Sequences

Escape Code Action
\033[l;cH M ove the cursor to line l and column c.
\033[nA M ove the cursor up n lines.
\033[nB M ove the cursor down n lines.
\033[nC M ove the cursor forward n characters.
\033[nD M ove the cursor backward n characters.
\033[2J Clear the screen and move the cursor to the upper left corner (line 0, column 0).
\033[K Clear from the cursor position to the end of the current line.
\033[s Store the current cursor position.
\033[u Recall the stored cursor position.

配色就这样吧

Part 4 – Common Tasks And Essential Tools

第十五章

Major Packaging System Families

Packaging System Distributions (Partial Listing)
Debian Style (.deb) Debian, Ubuntu, Xandros, Linspire
Red Hat Style (.rpm) Fedora, CentOS, Red Hat Enterprise Linux, OpenSUSE, Mandriva, PCLinuxOS

Packaging System Tools

Distributions Low-Level Tools High-Level Tools
Debian-Style dpkg apt-get aptitude
Fedora, Red Hat rpm yum
Enterprise Linux, CentOS . .

Package Search Commands

Style Command(s)
Debian apt-get update apt-cache search search_string
Red Hat yum search search_string

例子

# ubuntu
ecos@ubuntu:~$ apt-get install gvim     # 安装软件
ecos@ubuntu:~$ apt-get remove emacs     # 卸载软件

ecjÂÂ os@ubuntu:~$ apt-cache show emacs     # 查看在Debian-style系统对emacs的描述

# red hat
ecos@ubuntu:~$ rpm -U emacs-22.1-7.fc7-i386.rpm        # 更新现有的安装emacs版本
ecos@ubuntu:~$ rpm -qf /usr/bin/vim                    # 看看/usr/bin/vim安装信息

第十六章

储存媒体
mount                 - 挂载文件系统
umount                - 卸载文件系统
fsck                  - 检查和修复的文件系统
fdisk                 - 手动分区
mkfs                  - 创建文件系统
fdformat              - 格式化磁盘
dd                    - 写一个数据块直接导向装置
genisoimage (mkisofs) - 创建一个ISO 9660镜像文件
wodim (cdrecord)      - 将数据写到光学存储介质
md5sum                - 计算MD5校验

例子

# ubuntu
ecos@ubuntu:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro,commit=0)
proc on /proc type proc (rw,noexec,nosuid,nodev)
none on /sys type sysfs (rw,noexec,nosuid,nodev)
fusectl on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
none on /dev type devtmpfs (rw,mode=0755)
none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
none on /dev/shm type tmpfs (rw,nosuid,nodev)
none on /var/run type tmpfs (rw,nosuid,mode=0755)
none on /var/lock type tmpfs (rw,noexec,nosuid,nodev)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
/home/robotnik/.Private on /home/robotnik type ecryptfs (ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_unlink_sigs,ecryptfs_sig=c2a6969e54c5fac6,ecryptfs_fnek_sig=934169133215c307)gvfs-fuse-daemon on /home/robotnik/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=robotnik)

mount

命令格式:

mount [-t vfstype] [-o options] device dir
其中:
  1. -t vfstype 指定文件系统的类型, 通常不必指定. mount 会自动选择正确的类型. 常用类型有:
    • 光盘或光盘镜像:iso9660
    • DOS fat16文件系统:msdos
    • Windows 9x fat32文件系统:vfat
    • Windows NT ntfs文件系统:ntfs
    • Mount Windows文件网络共享:smbfs
    • UNIX(LINUX) 文件网络共享:nfs
  2. -o options 主要用来描述设备或档案的挂接方式. 常用的参数有:
    • loop:用来把一个文件当成硬盘分区挂接上系统
    • ro:采用只读方式挂接设备
    • rw:采用读写方式挂接设备
    • iocharset:指定访问文件系统所用字符集
  3. device 要挂接(mount)的设备
  4. dir设备在系统上的挂接点(mount point)

挂接光盘镜像文件
  1. 从光盘制作光盘镜像文件. 将光盘放入光驱, 执行下面的命令.
    cp /dev/cdrom /home/sunky/mydisk.iso
    或
    dd if=/dev/cdrom of=/home/sunky/mydisk.iso
    
    # 执行上面的任何一条命令都可将当前光驱里的光盘制作成光盘镜像文件/home/sunky/mydisk.iso
    
  2. 将文件和目录制作成光盘镜像文件, 执行下面的命令.
    mkisofs -r -J -V mydisk -o /home/sunky/mydisk.iso /home/sunky/ mydir
    # 这条命令将/home/sunky/mydir目录下所有的目录和文件制作成光盘镜像文件/home/sunky/mydisk.iso, 光盘卷标为:mydisk
    
  3. 光盘镜像文件的挂接(mount)
    # 建立一个目录用来作挂接点(mount point)
    mkdir /mnt/vcdrom
    
    # 使用/mnt/vcdrom就可以访问盘镜像文件mydisk.iso里的所有文件了.   
    mount -o loop -t iso9660 /home/sunky/mydisk.iso /mnt/vcdrom
    

第十七章

网络
本章会讲一下命令
ping         - 发送一个ICMP ECHO_REQUEST到网络主机
traceroute   - 打印路由跟踪数据包到网络主机
netstat      - 打印网络连接、路由表、接口统计
ftp          - 网络文件传输程序
wget         - 非交互式网络下载
ssh          - OpenSSH的SSH客户端(远程登录程序)

ping

ecos@ubuntu:~$ ping www.shopex.cn
PING shopex.cn (60.191.141.220) 56(84) bytes of data.
64 bytes from 60.191.141.220: icmp_req=1 ttl=52 time=10.8 ms
64 bytes from 60.191.141.220: icmp_req=2 ttl=52 time=53.7 ms
64 bytes from 60.191.141.220: icmp_req=3 ttl=52 time=40.7 ms
64 bytes from 60.191.141.220: icmp_req=4 ttl=52 time=19.7 ms

--- shopex.cn ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 10.891/31.287/53.784/16.915 ms

traceroute

跟踪路由
traceroute程序(一些系统使用类似tracepath方案代替, 如:ubuntu)显示了所有的“hops”上市所需的网络流量从本地系统指定的主机.
例如, 要看到采取到达路线
www.shopex.cn这样做:
ecos@ubuntu:~$ tracepath www.shopex.cn
 1:  192.168.51.125                                        0.118ms pmtu 1500
 1:  192.168.51.1                                          2.817ms
 1:  192.168.51.1                                          2.138ms
 2:  192.168.100.254                                     277.319ms
 3:  116.236.168.177                                      84.988ms
 4:  4ge1-ip-gl-016.online.sh.cn                         267.689ms
 5:  ^C

在输出中, 我们可以看到, 从我们的测试系统连接到www.shopex.cn需要遍历sixteen路由器.对于路由器提供的身份信息, 我们看到自己的主机名, IP地址和性能数据, 其中包括三个样本往返时间从本地系统到路由器.对于路由器不提供识别信息(因为路由器配置, 网络拥塞, 防火墙, 等), 我们认为, 在跳数为两线星号.

netstat

netstat程序是用于检查各种网络设置和统计.
通过使用它的许多选项, 我们可以看看各种功能在我们的网络设置.
使用"-ie"选项, 我们可以检查我们的系统的网络接口:

ecos@ubuntu:~$ netstat -ie
Kernel Interface table
eth0      Link encap:Ethernet  HWaddr 00:15:58:28:be:c0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:16

eth1      Link encap:Ethernet  HWaddr 00:16:6f:78:1a:64
          inet addr:192.168.51.125  Bcast:192.168.51.255  Mask:255.255.255.0
          inet6 addr: fe80::216:6fff:fe78:1a64/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:248383 errors:62 dropped:62 overruns:0 frame:0
          TX packets:62696 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:105306560 (105.3 MB)  TX bytes:8374233 (8.3 MB)
          Interrupt:21 Base address:0x2000 Memory:a8401000-a8401fff

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:516 errors:0 dropped:0 overruns:0 frame:0
          TX packets:516 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:537275 (537.2 KB)  TX bytes:537275 (537.2 KB)

ecos@ubuntu:~$ netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.51.0    *               255.255.255.0   U         0 0          0 eth1
link-local      *               255.255.0.0     U         0 0          0 eth1
default         192.168.51.1    0.0.0.0         UG        0 0          0 eth1

ftp

wget

另一种流行的命令行程序文件下载是wget的. 它是有用的同时从网络下载和FTP站点的内容.
单个文件, 多个文件, 甚至整个网站可以下载.
要下载linuxcommand.org第一页 我们可以这样做:
ecos@ubuntu:~$ wget http://linuxcommand.org/index.php
--2011-06-20 15:47:34--  http://linuxcommand.org/index.php
Resolving linuxcommand.org... 216.34.181.97
Connecting to linuxcommand.org|216.34.181.97|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3607 (3.5K) [text/html]
Saving to: `index.php'

     0K ...                                                   100% 49.5M=0s

2011-06-20 15:47:41 (49.5 MB/s) - `index.php' saved [3607/3607]

该方案的许多选项让wget来递归下载, 下载的文件背景(允许您注销而继续下载), 并完成下载一个部分下载的文件. 这些功能是有据可查的在其好于平均水平的手册页.

ssh

远程登录

例子

ecos@ubuntu:~$ ssh root@192.168.51.119
root@192.168.51.119's password:
Last login: Mon Jun 20 15:31:01 2011
[root@ecos9 ~]#
创建密钥免密码登录方法
ecos@ubuntu:~$ ssh-keygen -t ras
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ecos/.ssh/id_rsa):    # 密码不设置, 直接按Enter
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ecos/.ssh/id_rsa.
Your public key has been saved in /home/ecos/.ssh/id_rsa.pub.
The key fingerprint is:
75:19:9d:a3:68:60:6b:6d:4c:27:e7:72:d3:c3:44:5f ecos@ubuntu
The key's randomart image is:
+--[ RSA 2048]----+
|            .o..E|
|        o o oo=..|
|       . *.*o= ..|
|        o.B.= +  |
|       .So o . . |
|                 |
|                 |
|                 |
|                 |
+-----------------+
ecos@ubuntu:~$
这时候在主目录下生成.ssh/文件夹, 接下来我们只要把.ssh目录id_rsa.pub中的内容添加到目标主机中.ssh目录authorized_keys就完成了

试试

ecos@ubuntu:~$ ssh root@192.168.51.119
Last login: Mon Jun 20 15:54:06 2011 from 192.168.51.125

文件

当前日期: 2011-06-30 星期四

ssh-keygen - 生成、管理和转换认证密钥
描述
ssh-keygen 用于为 ssh(1)生成、管理和转换认证密钥, 包括 RSA 和 DSA 两种密钥.
密钥类型可以用 -t 选项指定. 如果没有指定则默认生成用于SSH-2的RSA密钥.
~/.ssh/identity
     该用户默认的 RSA1 身份认证私钥(SSH-1). 此文件的权限应当至少限制为"600".
     生成密钥的时候可以指定采用密语来加密该私钥(3DES).
     ssh(1) 将在登录的时候读取这个文件.
~/.ssh/identity.pub
     该用户默认的 RSA1 身份认证公钥(SSH-1). 此文件无需保密.
     此文件的内容应该添加到所有 RSA1 目标主机的 ~/.ssh/authorized_keys 文件中.
~/.ssh/id_dsa
     该用户默认的 DSA 身份认证私钥(SSH-2). 此文件的权限应当至少限制为"600".
     生成密钥的时候可以指定采用密语来加密该私钥(3DES).
     ssh(1) 将在登录的时候读取这个文件.
~/.ssh/id_dsa.pub
     该用户默认的 DSA 身份认证公钥(SSH-2). 此文件无需保密.
     此文件的内容应该添加到所有 DSA 目标主机的 ~/.ssh/authorized_keys 文件中.
~/.ssh/id_rsa
     该用户默认的 RSA 身份认证私钥(SSH-2). 此文件的权限应当至少限制为"600".
     生成密钥的时候可以指定采用密语来加密该私钥(3DES).
     ssh(1) 将在登录的时候读取这个文件.
~/.ssh/id_rsa.pub
     该用户默认的 RSA 身份认证公钥(SSH-2). 此文件无需保密.
     此文件的内容应该添加到所有 RSA 目标主机的 ~/.ssh/authorized_keys 文件中.
/etc/ssh/moduli
     包含用于 DH-GEX 的 Diffie-Hellman groups .

scp

SSH加密隧道, 通过网络复制文件. 首先, SCP(安全复制)被用来就像熟悉的CP程序复制文件.
最显着的区别在于, 源或目标路径名可能是前面有一个远程主机名, 后跟一个冒号.

比如我们用scp来完成上面那个密钥例子

ecos@ubuntu:~$ scp .ssh/id_rsa.pub root@192.168.51.119:test     # 复制密钥到192.168.51.119中root用户主文件夹test中
id_rsa.pub                                    100%  394     0.4KB/s   00:00
ecos@ubuntu:~$                                                  # 完成

第十八章

搜索文件
正如我们已经围绕我们的Linux系统徘徊, 有一点已变得非常清晰:
一个典型的Linux系统有很多文件!这引出了一个问题, “我们怎么找东西?”
我们已经知道, Linux文件系统是良好的组织结构已传下来的一种类Unix系统到下一代公约, 但文件数量之多可以提出一个严峻的问题.
在这一章中, 我们将着眼于两个用于查找系统上的文件的工具. 这些工具是:
locate      - 根据名字寻找文件
find        - 在目录中搜索文件

locate

查找文件的简便方法
该定位程序执行的路径快速数据库检索和输出每名称相匹配一个给定的子串.

例子

ecos@ubuntu:~$ locate /usr/share/vim/vim73
/usr/share/vim
/usr/share/vim/addons
/usr/share/vim/gvimrc
/usr/share/vim/registry
/usr/share/vim/vim73
/usr/share/vim/vimcurrent
...

ecos@ubuntu:~$ locate /usr/share/vim | grep vimrc
/usr/share/vim/gvimrc
/usr/share/vim/vimrc
/usr/share/vim/vimrc.tiny
/usr/share/vim/vim73/gvimrc_example.vim
/usr/share/vim/vim73/vimrc_example.vim

find

find File Types

File Type Description
b Block special device file
c Character special device file
d Directory
f Regular file
l Symbolic link
一些例子
ecos@ubuntu:~$ find ~
ecos@ubuntu:~$ find ~ | wc -l
4442
ecos@ubuntu:~$ find ~ -type d | wc -l
1059
ecos@ubuntu:~$ find ~ -type f | wc -l
3377
find Size Units
Character Unit
b 512 byte blocks. This is the default if no unit is specified.
c Bytes
w Two byte words
k Kilobytes (Units of 1024 bytes)
M Megabytes (Units of 1048576 bytes)
G Gigabytes (Units of 1073741824 bytes)

ecos@ubuntu:~$ find /host/icore/pictures/imgs/ -name "*.jpg" | wc -l
26

ecos@ubuntu:~$ find /host/icore/pictures/ -type f -name "*.jpg -size +100k | wc -l
33
自定义操作
-exec command {} ;

例子

ecos@ubuntu:~$ find /host/icore/doc/ -type f -name 'file*' -ok ls -l '{}' ';'
< ls ... /host/icore/doc/file1.log > ?
< ls ... /host/icore/doc/file2.log > ?
< ls ... /host/icore/doc/file4.log > ?
< ls ... /host/icore/doc/file5.log > ?
< ls ... /host/icore/doc/file6.log > ?
< ls ... /host/icore/doc/file7.log > ?
...

ecos@ubuntu:~$ find /host/icore/doc/ -type f -name 'file*' -exec ls -l '{}' ';'
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file1.log
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file2.log
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file4.log
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file5.log
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file6.txt
-rwxrwxrwx 1 root root 0 2011-06-21 14:58 /host/icore/doc/file7.txt

ecos@ubuntu:~$ find /host/icore/doc/ -type f -name 'file*' -exec ls -l '{}' +
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file1.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file2.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file4.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file5.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file6.txt
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file7.txt

xargs
xargs命令执行了一个有趣的功能. 它接受来自标准输入的输入, 并将其转换成一个指定的命令的参数列表.
ecos@ubuntu:~$ find /host/icore/doc/ -type f -name 'file*' -pirnt | xargs ls -l
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file1.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file2.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file4.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file5.log
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file6.txt
-rwxrwxrwx 1 root root 0 2011-06-21 15:12 /host/icore/doc/file7.txt
A Return To The Playground
有用的东西呀, 看了就知道!

例子

ecos@ubuntu:~$ mkdir -p /host/icore/doc/dir-{00{1..9},0{10..99},100}
ecos@ubuntu:~$ ls /host/icore/doc
dir-001  dir-013  dir-025  dir-037  dir-049  dir-061  dir-073  dir-085  dir-097
dir-002  dir-014  dir-026  dir-038  dir-050  dir-062  dir-074  dir-086  dir-098
dir-003  dir-015  dir-027  dir-039  dir-051  dir-063  dir-075  dir-087  dir-099
dir-004  dir-016  dir-028  dir-040  dir-052  dir-064  dir-076  dir-088  dir-100
dir-005  dir-017  dir-029  dir-041  dir-053  dir-065  dir-077  dir-089
dir-006  dir-018  dir-030  dir-042  dir-054  dir-066  dir-078  dir-090
dir-007  dir-019  dir-031  dir-043  dir-055  dir-067  dir-079  dir-091
dir-008  dir-020  dir-032  dir-044  dir-056  dir-068  dir-080  dir-092
dir-009  dir-021  dir-033  dir-045  dir-057  dir-069  dir-081  dir-093
dir-010  dir-022  dir-034  dir-046  dir-058  dir-070  dir-082  dir-094
dir-011  dir-023  dir-035  dir-047  dir-059  dir-071  dir-083  dir-095
dir-012  dir-024  dir-036  dir-048  dir-060  dir-072  dir-084  dir-096

ecos@ubuntu:~$ touch /host/icore/doc/dir-{00{1..9},0{10..99},100}/file-{A..Z}
ecos@ubuntu:~$ ls /host/icore/doc/dir-001
file-A  file-D  file-G  file-J  file-M  file-P  file-S  file-V  file-Y
file-B  file-E  file-H  file-K  file-N  file-Q  file-T  file-W  file-Z
file-C  file-F  file-I  file-L  file-O  file-R  file-U  file-X

ecos@ubuntu:~$ find /host/icore/doc -type f -name 'file-A' | wc -l
100

第十九章

归档和备份
对计算机系统管理员的主要任务之一是保持系统的数据安全. 这样做的一个方法是通过执行系统的文件及时备份.
即使你不是系统管理员, 它往往是有益的, 使事物的复制和移动文件从一个地方到大的集合地点, 从设备到设备.
在这一章中, 我们将着眼于几个用于管理文件集合的共同方案. 有文件的压缩方案:
gzip  - 压缩或扩展文件
bzip2 - 块排序文件压缩

归档方案:
tar   - 磁带归档工具
zip   - 打包和压缩文件

和文件同步程序:
rsync - 远程文件和目录同步

压缩文件

gzip
gzip的程序是用来压缩一个或多个文件. 当执行时, 它取代了原来的压缩版本的原始文件.
相应的用gunzip程序用于恢复到原来的压缩文件, 压缩形式. 这里是一个例子:
ecos@ubuntu:~$ gzip foo.txt
ecos@ubuntu:~$ gzip -tv foo.txt.gz
foo.txt.gz: OK
ecos@ubuntu:~$ gzip -d foo.txt.gz

接下来, 我们测试了压缩版本的完整性, 使用- t和- v选项.最后, 我们解压缩后的文件恢复到其原来的形式.gzip的, 也可以用于通过标准输入和输出有趣的方式:

ecos@ubuntu:~$ ls -l /etc | gzip > foo.txt.gz
ecos@ubuntu:~$ gunzip foo.txt
ecos@ubuntu:~$ gunzip -c foo.txt | less

bzip
类似于GZIP, 但使用不同的压缩算法, 实现了在压缩成本的压缩速度更高的水平.
在大多数方面, 它工作在相同的方式为gzip的. 使用bzip2压缩的文件扩展名为BZ2表示:
ecos@ubuntu:~$ ls -l /etc > foo.txt
ecos@ubuntu:~$ ls -l foo.txt
-rw-r--r-- 1 me     me     15738 2011-6-21 17:24 foo.txt
ecos@ubuntu:~$ bzip2 foo.txt
ecos@ubuntu:~$ ls -l foo.txt.bz2
-rw-r--r-- 1 me     me     2792  2011-6-21 17:24 foo.txt.bz2
ecos@ubuntu:~$ bunzip2 foo.txt.bz2

归档文件

tar

在软件类Unix的世界中, tar程序是归档文件的经典工具. 它的名字, 磁带归档短, 揭示了作为制作备份磁带工具的根源. 虽然它仍然使用了传统的任务, 它同样在其他存储设备以及娴熟. 我们经常看到的文件名结尾的扩展名. tar. tgz这表明一个“plain”和gzip压缩的tar归档文件归档, 分别为. 一个tar归档可以由一个独立的文件, 一个或多个目录层次结构, 或两者的混合组.

该命令的语法是这样的:

tar mode[options] pathname...
tar Modes
Mode Description
c 创建从一个文件/或目录列表归档
x 提取文档
r 追加指定路径到归档结束
t 列出存档的内容

例子

ecos@ubuntu:~$ mkdir -p playground/dir-{00{1..9},{0{10,99},100}}
ecos@ubuntu:~$ touch playground/dir-{00{1..9},0{10..99},100}/file-{A..Z}}
# 用tar归档
ecos@ubuntu:~$ tar cf playground.tar playground
# 解压
ecos@ubuntu:~$ tar xf playground.tar
日常应用
tar cf file.tar files     - 创建包含 files 的 tar 文件file.tar
tar xf file.tar           - 从 file.tar 提取文件
tar czf file.tar.gz files - 使用 Gzip 压缩创建tar 文件
tar xzf file.tar.gz       - 使用 Gzip 提取 tar 文件
tar cjf file.tar.bz2      - 使用 Bzip2 压缩创建 tar 文件
tar xjf file.tar.bz2      - 使用 Bzip2 提取 tar 文件
gzip file                 - 压缩 file 并重命名为 file.gz
gzip -d file.gz           - 将 file.gz 解压缩为 file
例子
# 如果在 playground 里面找到 file-A 执行 tar 命令
ecos@ubuntu:~$ find playground -name 'file-A' -exec tar czvf playground.tar.gz '{}' '+'
# 如果找到把它压缩, 找不到 playground里面为空
ecos@ubuntu:~$ find playground -name 'file-A' | tar czvf playground.tar.gz -T -

# 执行之后可以查看里面的元素
ecos@ubuntu:~$ tar tzvf playground.tar.gz
or
ecos@ubuntu:~$ tar tzvf playground.tar.gz | wc -l

zip

用法

# 压缩
zip -r filename.zip filename
# 解压
unzip filename.zip
# 查看
unzip -l filename.zip
例子
ecos@ubuntu:~$ find playground -name "file_A" | zip -@ file-A.zip
zip error: Nothing to do! (file-A.zip)

ecos@ubuntu:~$ find playground -name "file-A" | zip -@ file-A.zip
  adding: playground/dir_03/file-A (stored 0%)
  adding: playground/dir_06/file-A (stored 0%)
  adding: playground/dir_10/file-A (stored 0%)
  adding: playground/dir_04/file-A (stored 0%)
  adding: playground/dir_05/file-A (stored 0%)
  adding: playground/dir_07/file-A (stored 0%)
  adding: playground/dir_08/file-A (stored 0%)
  adding: playground/dir_09/file-A (stored 0%)
  adding: playground/dir_01/file-A (stored 0%)
  adding: playground/dir_02/file-A (stored 0%)
ecos@ubuntu:~$

同步文件和目录

Rsync(remote synchronize)是一个远程数据同步工具, 可通过LAN/WAN快速同步多台主机间的文件 Rsync使用所谓的“Rsync算法”来使本地和远程两个主机之间的文件达到同步, 这个算法只传送两个文件的不同部分, 而不是每次都整份传送, 因此速度相当快.

例子

ecos@ubuntu:~$ ls
playground
ecos@ubuntu:~$ rsync -av foo
sending incremental file list
drwxr-xr-x        4096 2011/06/27 12:48:26 playground
drwxr-xr-x        4096 2011/06/27 14:22:56 playground/dir_01
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_01/file-A
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_01/file-B
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_01/file-C
...
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_10/file-X
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_10/file-Y
-rw-r--r--           0 2011/06/27 12:49:02 playground/dir_10/file-Z

sent 2076 bytes  received 23 bytes  4198.00 bytes/sec
total size is 0  speedup is 0.00


ecos@ubuntu:~$ touch playground/dir_01/file-0
ecos@ubuntu:~$ rsync -av playground foo
sending incremental file list
playground/dir_01/
playground/dir_01/file-0

sent 2133 bytes  received 45 bytes  4356.00 bytes/sec
total size is 0  speedup is 0.00
ecos@ubuntu:~$

第二十章

正则表达式
在计算机科学中, 是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串. 在很多文本编辑器或其他工具里, 正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容. 许多程序设计语言都支持利用正则表达式进行字符串操作.

grep

语法

grep [options] regex [file...]
ecos@ubuntu:~$ ls /usr/bin | grep zip
funzip
gpg-zip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
grep Options
Option Desciption
-i 忽略字符大小写
-v 反转查找
-c 计算符合范本样式的列数
-l 列出文件内容符合指定的范本样式的文件名称
-L 列出文件内容不符合指定的范本样式的文件名称
-n 在显示符合范本样式的那一列之前, 标示出该列的列数编号
-h 在显示符合范本样式的那一列之前, 不标示该列所属的文件名称
-E 采用规则表示式去解释样式

例子

ecos@ubuntu:~$ ls /bin > dirlist-bin.txt
ecos@ubuntu:~$ ls /usr/bin > dirlist-usr-bin.txt
ecos@ubuntu:~$ ls /sbin > dirlist-sbin.txt
ecos@ubuntu:~$ ls /usr/sbin > dirlist-usr-sbin.txt

ecos@ubuntu:~$ ls dirlist*.txt
dirlist-bin.txt  dirlist-sbin.txt  dirlist-usr-bin.txt  dirlist-usr-sbin.txt

ecos@ubuntu:~$ grep bzip dirlist*.txt
dirlist-bin.txt:bzip2
dirlist-bin.txt:bzip2recover

ecos@ubuntu:~$ grep -l bzip dirlist*.txt
dirlist-bin.txt

ecos@ubuntu:~$ grep -L bzip dirlist*.txt
dirlist-sbin.txt
dirlist-usr-bin.txt
dirlist-usr-sbin.txt

正则表达式
包括用来指定更复杂的匹配元字符. 表达式元字符包括以下内容:
^ $ . [ ] { } - ? * + ( ) | \

一些例子

ecos@ubuntu:~$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
gunzip
gzip
funzip
gpg-zip
mzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
锚(Anchors)
插入符号(^)和美元符号($)字符被视为在正则表达式锚.
这意味着, 正则表达式中(^)表示开头或($)表示结尾:
例子
ecos@ubuntu:~$ grep -h '^zip' dirlist*.txt
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit

ecos@ubuntu:~$ grep -h 'zip$' dirlist*.txt
gunzip
gzip
funzip
gpg-zip
preunzip
prezip
unzip
zip

ecos@ubuntu:~$ grep -h '^zip$' dirlist*.txt
zip

ecos@ubuntu:~$ grep -h '[bg]zip' dirlist*.txt
bzip2
bzip2recover
gzip

ecos@ubuntu:~$ grep -h '[^bg]zip' dirlist*.txt
bunzip2
gunzip
funzip
gpg-zip
preunzip
prezip
prezip-bin
unzip
unzipsfx

ecos@ubuntu:~$ grep -h '^[A-Z]' dirlist*.txt
MAKEDEV
ControlPanel
GET
HEAD
POST
X
X11
Xorg
MAKEFLOPPIES
NetworkManager
NetworkManagerDispatcher

ecos@ubuntu:~$ ls /usr/sbin/[ABCDEFGHIJKLMNOPQRSTUVWXYZ]*
/usr/sbin/NetworkManager

ecos@ubuntu:~$ ls /usr/sbin/[A-Z]*
/usr/sbin/bccmd
/usr/sbin/biosdecode
/usr/sbin/bluetoothd
/usr/sbin/chat
...

ecos@ubuntu:~$ echo $LANG
en_US.UTF-8

POSIX Character Classes

Character Class Description
[:alnum:] The alphanumeric characters. In ASCII, equivalent to: [A-Za-z0-9]
[:word:] The same as [:alnum:], with the addition of the underscore (_) character.
[:alpha:] The alphabetic characters. In ASCII, equivalent to: [A-Za-z]
[:blank:] Includes the space and tab characters.
[:cntrl:] The ASCII control codes. Includes the ASCII characters zero through thirty-one and 127.
[:digit:] The numerals zero through nine.
[:graph:] The visible characters. In ASCII, it includes characters 33 through 126.
[:lower:] The lowercase letters.
[:punct:] The punctuation characters. In ASCII, equivalent to: [-!"#$%&'()*+,./:;<=>?@[\\\]_`{|}~]
[:print:] The printable characters. All the characters in [:graph:] plus the space character.
[:space:] The whitespace characters including space, tab, carriage return, newline, vertical tab, and form feed. In ASCII, equivalent to: [ \t\r\n\v\f]
[:upper:] The upper case characters.
[:xdigit:] Characters used to express hexadecimal numbers. In ASCII, equivalent to: [0-9A-Fa-f]

例子

ecos@ubuntu:~$ ls /usr/sbin/[[:upper:]]*
/usr/sbin/MAKEFLOPPIES
/usr/sbin/NetworkManagerDispatcher
/usr/sbin/NetworkManager

ecos@ubuntu:~$ echo "AAA" | grep AAA
AAA

ecos@ubuntu:~$ echo "BBB" | grep AAA        # 什么都没有
ecos@ubuntu:~$
我用grep匹配找到的时候会打印出来, 如果不匹配什么都不输出
ecos@ubuntu:~$ echo "AAA" | grep -E 'AAA|BBB'
AAA
ecos@ubuntu:~$ echo "BBB" | grep -E 'AAA|BBB'
BBB
ecos@ubuntu:~$ echo "CCC" | grep -E 'AAA|BBB'
ecos@ubuntu:~$
要结合其他正则表达式的元素交替, 我们可以用()来分隔交替:
ecos@ubuntu:~$ grep -Eh '^(bz|gz|zip)' dirlist*.txt
bzcat
bzcmp
bzdiff
bzegrep
bzexe
bzfgrep
bzgrep
bzip2
bzip2recover
bzless
bzmore
gzexe
gzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
ecos@ubuntu:~$ grep -Eh '^bz|gz|zip' dirlist*.txt
bunzip2
bzcat
bzcmp
bzdiff
bzegrep
bzexe
bzfgrep
bzgrep
bzip2
bzip2recover
bzless
bzmore
gunzip
gzexe
gzip
funzip
gpg-zip
mzip
preunzip
prezip
prezip-bin
tgz
unzip
unzipsfx
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit
看出两者的区别了吧

再来看一些例子:

ecos@ubuntu:~$ echo "(555) 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]$'
(555) 123-4567

ecos@ubuntu:~$ echo "555 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
555 123-4567

ecos@ubuntu:~$ echo "AAA 123-4567" | grep -E '^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$'
ecos@ubuntu:~$
知道为什么最后一个例子什么都么输出吗?

在这里, 我们看到, 表达式匹配的电话号码两种形式, 但不匹配一个包含非数字字符.

大小写的例子

ecos@ubuntu:~$ echo "This works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This works.

ecos@ubuntu:~$ echo "This Works." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
This Works.

ecos@ubuntu:~$ echo "this does not." | grep -E '[[:upper:]][[:upper:][:lower:] ]*\.'
ecos@ubuntu:~$

下面的例子用 ^([[:alpha:]]+ ?)+$

ecos@ubuntu:~$ echo "This that" | grep -E '^([[:alpha:]]+ ?)+$'
This that
ecos@ubuntu:~$ echo "a b c" | grep -E '^([[:alpha:]]+ ?)+$'
a b c
ecos@ubuntu:~$ echo "a b 9" | grep -E '^([[:alpha:]]+ ?)+$'
ecos@ubuntu:~$ echo "abc d" | grep -E '^([[:alpha:]]+ ?)+$'
ecos@ubuntu:~$
我们看到, 这个表达式不匹配行'a b 9', 因为它包含一个非字母字符, 也不符合'abc d', 因为多个空格字符分隔字符'c'和'd'.

Specifying The Number Of Matches

Specifier Meaning
{n} Match the preceding element if it occurs exactly n times.
{n,m} Match the preceding element if it occurs at least n times, but nomore than m times.
{n,} Match the preceding element if it occurs n or more times.
{,m} Match the preceding element if it occurs no more than m times.

例子

ecos@ubuntu:~$ echo "(555) 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
(555) 123-4567
ecos@ubuntu:~$ echo "555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
555 123-4567
ecos@ubuntu:~$ echo "5555 123-4567" | grep -E '^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$'
ecos@ubuntu:~$
我们可以看到, 我们的修订既表达可以成功验证使用和不使用括号中的数字, 而拒绝那些不正确格式的数字.

复杂一点的例子

ecos@ubuntu:~$ for i in {1..10}; do echo "(${RANDOM:0:3}) ${RANDOM:0:3}-${RANDOM:0:4}" >> phonelist.txt; done
此命令将产生一个名为phonelist.txt包含着十个电话号码的文件. 每个命令重复时间, 就有10个号码被添加到列表中.我们也可以改变附近的命令开始值10产生更多或更少的电话号码. 如果我们检查该文件的内容, 但是, 我们看到我们有一个问题:
ecos@ubuntu:~$ cat phonelist.txt
(325) 220-4767
(336) 210-1370
(425) 112-2432
(271) 364-2293
(269) 647-3245
(268) 289-2095
(134) 126-2845
(190) 146-1077
(485) 191-1096
(176) 330-1667
这些数字有些畸形, 这是我们的目的完美的, 因为我们将使用grep来验证它们.一个有用的验证方法是将扫描文件为无效号码, 并显示在屏幕上产生的清单:
ecos@ubuntu:~$ cat phonelist.txt
(232) 298-2265
(624) 381-1078
(540) 126-1980
(874) 163-2885
(286) 254-2860
(292) 108-518
(129) 44-1379
(458) 273-1642
(686) 299-8268
(198) 307-2440

ecos@ubuntu:~$ grep -Ev '^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$' phonelist.txt
(292) 108-518
(129) 44-1379
ecos@ubuntu:~$
在这里, 我们使用-v选项, 以产生逆相匹配, 使我们只输出列表中的行不匹配指定表达式.表达式本身包含两端的锚元字符, 以确保数量两端没有多余的字符. 这个表达式还要求括号中存在一个有效的数字不像我们以前的电话号码.

Finding Ugly Filenames With find

find命令支持在基于正则表达式测试. 有一个重要的考虑因素, 在使用时, 请记住在找到与grep的正则表达式.而grep将打印一行时行包含一个字符串匹配一个表达式, 找到需要的路径完全匹配正则表达式. 在下面的例子中, 我们将使用一个正则表达式找到找到每一个路径名中包含任何字符, 是不是下面的一组成员:

[-_./0-9a-zA-Z]

find . -regex '.*[^-_./0-9a-zA-Z].*'

例子

ecos@ubuntu:~$ locate --regex 'bin/(bz|gz|zip)'
/bin/bzcat
/bin/bzcmp
/bin/bzdiff
/bin/bzegrep
/bin/bzexe
/bin/bzfgrep
/bin/bzgrep
/bin/bzip2
/bin/bzip2recover
/bin/bzless
/bin/bzmore
/bin/gzexe
/bin/gzip
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit
/usr/lib/klibc/bin/gzip

第二十一章

进程处理
cat
sort
uniq
cut
paste
join
comm
diff
patch
tr
sed
aspell

cat

看下面的例子

ecos@ubuntu:~$ cat > foo.txt            # 下面的内容前面是一个<tab>行尾有个<space>
    The quick brown fox jumped over the lazy dog.
(<ctrl>+d:退出)
ecos@ubuntu:~$
# 然后我们用 cat 的 -A 参数显示foo.txt
ecos@ubuntu:~$ cat -A foo.txt
^IThe quick brown fox jumped over the lazy dog. $
ecos@ubuntu:~$
正如我们可以看到的结果, 在我们的文字制表符为代表的^I这是一种常见的符号, 这意味着“控制-I”,如它的出现, 是作为一个制表符相同. 我们也看到, $出现在该行的真正目的, 这说明我们的文字包含尾随空格.

继续看例子

ecos@ubuntu:~$ cat > foo.txt
The quick brown fox

jumped over the lazy dog.
ecos@ubuntu:~$ cat -ns foo.txt
     1	The quick brown fox
     2
     3	jumped over the lazy dog.
ecos@ubuntu:~$

sort

排序文件、对已排序的文件进行合并, 并检查文件以确定它们是否已排序.

使用相同的技术, 我们与 cat 使用, 我们可以证明直接从键盘的标准输入处理:
ecos@ubuntu:~$ sort > foo.txt
c
b
a
ecos@ubuntu:~$ cat foo.txt
a
b
c

ecos@ubuntu:~$ touch file{1..3}.txt final_sorted_list.txt
ecos@ubuntu:~$ cat > file1.txt
aaa
ecos@ubuntu:~$ cat > file2.txt
bbb
ecos@ubuntu:~$ cat > file3.txt
ccc
ecos@ubuntu:~$ sort file1.txt file2.txt file3.txt > final_sorted_list.txt
ecos@ubuntu:~$ cat final_sorted_list.txt
aaa
bbb
ccc
sort 有几个有趣的选项, 一下是清单:
Option Long OPtion Description
-b --ignore-leading-blanks 默认情况下, 执行排序对整个线, 在该行第一个字符开始. 此选项会导致排序忽略前导空格线, 并计算排序的基础上, 第一个非空白字符就行了
-f --ignore-case 使排序不区分大小写
-n --numeric-sort 执行排序基于字符串的数字评价. 使用此选项允许在执行排序的数值默认情况下, 排序是对整个线路进行, 与在该行第一个字符开始. 此选项会导致排序忽略前导空格线, 并计算排序的基础上, 第一个非空白字符就行了. 而不是字母值
-r --reverse 排序顺序相反. 结果递减而不是递增的顺序
-k --key=field1[,field2] 一个关键字段分类的基础上,从field1 field2所在地,而非整个生产线. 看到讨论如下
-m --merge 对待每一个预排序的每个参数的文件名. 合并不执行任何附加的排序成一个排序结果多个文件
-o --output=file 发送的有序输出到文件, 而不是标准输出
-t --field-separator=char 定义字段分隔符. 默认情况下字段由空格分隔或制表符

例子

ecos@ubuntu:~$ du -s /usr/share/* | head
576	/usr/share/aclocal
168	/usr/share/aclocal-1.11
28	/usr/share/acpi-support
8	/usr/share/adduser
352	/usr/share/adium
196	/usr/share/alacarte
444	/usr/share/alsa
8	/usr/share/alsa-base
49652	/usr/share/app-install
28	/usr/share/application-registry
在这个例子中, 我们将 du 的结果用 head 得到结果的前十行.

例子

ecos@ubuntu:~$ du -s /usr/share/* | sort -nr | head
98704	/usr/share/icons
73200	/usr/share/fonts
66076	/usr/share/doc
59548	/usr/share/gnome
49652	/usr/share/app-install
32852	/usr/share/midi
29936	/usr/share/pyshared
28396	/usr/share/locale
25420	/usr/share/vim
24556	/usr/share/libreoffice
通过使用-nr选项, 我们产生一个反向的数字排序, 最大的值出现在结果第一的位置.这种情况因为数值在每行的开头发生. 但是, 如果我们要排序的行内发现了一些价值为一般的清单?例如, 一个ls-l的结果:
ecos@ubuntu:~$ ls -l /usr/bin | head
total 162872
-rwxr-xr-x 1 root   root      30244 2011-02-23 21:22 [
lrwxrwxrwx 1 root   root          8 2011-06-19 20:15 2to3 -> 2to3-2.7
-rwxr-xr-x 1 root   root         96 2011-04-12 03:07 2to3-2.7
-rwxr-xr-x 1 root   root     105028 2011-04-27 00:21 a2p
lrwxrwxrwx 1 root   root         25 2011-06-19 17:09 aclocal -> /etc/alternatives/aclocal
-rwxr-xr-x 1 root   root      31181 2010-12-09 07:19 aclocal-1.11
-rwxr-xr-x 1 root   root      13860 2011-04-21 01:10 aconnect
-rwxr-xr-x 1 root   root       5536 2010-11-22 09:25 acpi_fakekey
-rwxr-xr-x 1 root   root       9756 2011-01-07 21:11 acpi_listen
我们可以把 ls -l 和 sort -nr 结合使用
ecos@ubuntu:~$ ls -l /usr/bin | sort -nr -k 5 | head
-rwxr-xr-x 1 root   root    7725068 2011-05-03 07:38 php5-cgi
-rwxr-xr-x 1 root   root    7716844 2011-05-03 07:38 php5
-rwxr-xr-x 1 root   root    7497484 2011-05-10 04:26 net.samba3
-rwxr-xr-x 1 root   root    6736504 2011-05-10 04:26 rpcclient
-rwxr-xr-x 1 root   root    6581944 2011-05-10 04:26 smbcacls
-rwxr-xr-x 1 root   root    6540980 2011-05-10 04:26 smbget
-rwxr-xr-x 1 root   root    6512344 2011-05-10 04:26 smbclient
-rwxr-xr-x 1 root   root    6438584 2011-05-10 04:26 smbpasswd
-rwxr-xr-x 1 root   root    6434488 2011-05-10 04:26 smbcquotas
-rwxr-xr-x 1 root   root    6414004 2011-05-10 04:26 smbtree

uniq

uniq 命令删除文件中的重复行

重复行通常不会造成问题, 但是有时候它们的确会引起问题. 此时, 不必花上一个下午
的时间来为它们编制过滤器, uniq 命令便是唾手可得的好工具.了解一下它是如何节省
您的时间和精力的.

我们看看 uniq 的用法

ecos@ubuntu:~$ cat happybirthday.txt
Happy Birthday to You!
Happy Birthday to You!
Happy Birthday Dear Tux!
Happy Birthday to You!

ecos@ubuntu:~$ sort happybirthday.txt
Happy Birthday Dear Tux!
Happy Birthday to You!
Happy Birthday to You!
Happy Birthday to You!

ecos@ubuntu:~$ sort happybirthday.txt | uniq
Happy Birthday Dear Tux!
Happy Birthday to You!
使用 -u唯一] 选项
ecos@ubuntu:~$ sort happybirthday.txt | uniq -u
Happy Birthday Dear Tux!
ecos@ubuntu:~$ sort happybirthday.txt | uniq -d
Happy Birthday to You!
-c[统计]
ecos@ubuntu:~$ sort happybirthday.txt | uniq -uc
      1 Happy Birthday Dear Tux!
ecos@ubuntu:~$ sort happybirthday.txt | uniq -dc
      3 Happy Birthday to You!
就算 uniq 对完整的行进行比较, 它仍然会很有用, 但是那并非该命令的全部功能. 特别方便的是:使用 -f 选项, 后面跟着要跳过的字段数, 它能够跳过给定数目的字段. 当您查看系统日志时这非常有用. 通常, 某些项要被复制许多次, 这使得查看日志很难. 使用简单的 uniq 无法完成任务, 因为每一项都以不同的时间戳记开头. 但是如果您告诉它跳过所有的时间字段, 您的日志一下子就会变得更加便于管理. 试一试 uniq -f 3 /var/log/messages , 亲眼看看.还有另一个选项 -s , 它的功能就像 -f 一样, 但是跳过给定数目的字符. 您可以一起使用 -f 和 -s . uniq 先跳过字段, 再跳过字符. 如果您只想使用一些预先设置的字符进行比较, 那么该怎么办呢?试试看 -w 选项.

cut

显示每行从开头算起 num1 到 num2 的文字.

命令格式

cut -b list [-n] [file...]
cut -c list [file...]
cut -f list [-d delim] [-s] [file...]
-b   表示字节 (byte)
-c   表示字符 (char)
-f   表示字段 (field)
-d   表示分割夫 默认为tab
-n   具体的数字
list 表示范围 范围是从1开始 -b1-3表示

例子

ecos@ubuntu:~$ cat /etc/passwd | head
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh

# 取用户名
ecos@ubuntu:~$ cut -d ':' -f 1 /etc/passwd | head
root
daemon
bin
sys
sync
games
man
lp
mail
news

# 分隔符是: 取第一个字段 只想取前面八个字符
ecos@ubuntu:~$ cut -c1-8 /etc/passwd | head
root:x:0
daemon:x
bin:x:2:
sys:x:3:
sync:x:4
games:x:
man:x:6:
lp:x:7:7
mail:x:8
news:x:9

# 从第八个字符开始到行尾
ecos@ubuntu:~$ cut -b 8- /etc/passwd | head
0:0:root:/root:/bin/bash
x:1:1:daemon:/usr/sbin:/bin/sh
:2:bin:/bin:/bin/sh
:3:sys:/dev:/bin/sh
4:65534:sync:/bin:/bin/sync
:5:60:games:/usr/games:/bin/sh
:12:man:/var/cache/man:/bin/sh
7:lp:/var/spool/lpd:/bin/sh
8:8:mail:/var/mail:/bin/sh
9:9:news:/var/spool/news:/bin/sh

# 把前5位的用户名和该用户的shell输出来
ecos@ubuntu:~$ cut -d: -f 1,7 /etc/passwd
root:/bin/bash
daemon:/bin/sh
bin:/bin/sh
sys:/bin/sh
sync:/bin/sync
games:/bin/sh
man:/bin/sh
lp:/bin/sh
mail:/bin/sh
news:/bin/sh

paste

paste 工具可以对文件中的域进行合并. 它从每个源文件中提取一行内容, 并将其与另外一个源文件中的一行内容合并在一起.

举例来说, 假设文件 “fileone” 的内容如下所示:

ecos@ubuntu:~$ cat file1.txt
aaa
bbb
ccc
ecos@ubuntu:~$ cat file2.txt
xxx
yyy
zzz
# 下面的命令将这两个文件的内容合并在一起, 如下所示:
ecos@ubuntu:~$ paste file1.txt file2.txt
aaa     xxx
bbb     yyy
ccc     zzz

ecos@ubuntu:~$ paste file1.txt file2.txt > file3.txt
ecos@ubuntu:~$ cate file3.txt
aaa    xxx                              # 成功粘贴到file3.txt
bbb    yyy
ccc    zzz

ecos@ubuntu:~$ paste file1.txt file2.txt >> file3.txt
aaa    xxx
bbb    yyy
ccc    zzz
aaa    xxx
bbb    yyy
ccc    zzz                              # 这个命令会把 file1.txt 和 file2.txt 文件中的内容添加到 file3.txt 文件内容的最后

join

根据公共字段(关键字)来合并两个文件的数据行.
因此最简单的使用方式就是指定两个数据文件名, 这两个文件的第一列就是公共字段, 字段 之间以空白分隔.

内连接(inner join)                             格式:join <FILE1> <FILE2>
左连接(left join, 左外连接, left outer join)   格式:join -a1 <FILE1> <FILE2>
右连接(right join, 右外连接,right outer join)  格式:join -a2 <FILE1> <FILE2>
全连接(full join, 全外连接, full outer join)   格式:join -a1 -a2 <FILE1> <FILE2>

指定分隔符:

-t <CHAR>
比如:-t ':' 使用冒号作为分隔符. 默认的分隔符是空白.


指定输出字段:
-o <FILENO.FIELDNO> ...

其中FILENO=1表示第一个文件, FILENO=2表示第二个文件, FIELDNO表示字段序号, 从1开始编号. 默认会全部输出, 但关键字列只输出一次.

比如:-o 1.1 1.2 2.2 表示输出第一个文件的第一个字段、第二个字段, 第二个文件的第二个字段.
例子
ecos@ubuntu:~$ cat month_cn.txt
1       一月
2       二月
3       三月
4       四月
5       五月
6       六月
7       七月
8       八月
9       九月
10      十月
11      十一月
12      十二月
13      十三月

ecos@ubuntu:~$ cat month_en.txt
1       January
2       February
3       March
4       April
5       May
6       June
7       July
8       August
9       September
10      October
11      November
12      December
14      MonthUnknown

两个文件中文版的多了13月, 英文版的多了14月

示例一 内连接(忽略不匹配的行)
# 不指定任何参数的情况下使用join命令, 就相当于数据库中的内连接, 关键字不匹配的行不会输出.

ecos@ubuntu:~$ join month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
示例二 左连接(又称左外连接, 显示左边所有记录)
# 显示左边文件中的所有记录, 右边文件中没有匹配的显示空白.

ecos@ubuntu:~$ join -a1 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
13 十三月
示例三 右连接(又称右外连接, 显示右边所有记录)
# 显示右边文件中的所有记录, 左边文件中没有匹配的显示空白.

ecos@ubuntu:~$ join -a2 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
14 MonthUnknown
示例四 全连接(又称全外连接, 显示左边和右边所有记录)
ecos@ubuntu:~$ join -a1 -a2 month_cn.txt month_en.txt
1 一月 January
2 二月 February
3 三月 March
4 四月 April
5 五月 May
6 六月 June
7 七月 July
8 八月 August
9 九月 September
10 十月 October
11 十一月 November
12 十二月 December
13 十三月
14 MonthUnknown
示例五 指定输出字段
# 比如参数 -o 1.1 表示只输出第一个文件的第一个字段.

ecos@ubuntu:~$ join -o 1.1 month_cn.txt month_en.txt
1
2
3
4
5
6
7
8
9
10
11
12

ecos@ubuntu:~$ join -o 1.1 2.2 month_cn.txt month_en.txt
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December

ecos@ubuntu:~$ join -o 1.1 2.2 1.2 month_cn.txt month_en.txt
1 January 一月
2 February 二月
3 March 三月
4 April 四月
5 May 五月
6 June 六月
7 July 七月
8 August 八月
9 September 九月
10 October 十月
11 November 十一月
12 December 十二月

ecos@ubuntu:~$ join -o 1.1 2.3  month_cn.txt month_en.txt # 2.3什么都没有
1
2
3
4
5
6
7
8
9
10
11
12

comm

看例子不说话

ecos@ubuntu:~$ cat > file1.txt
a
b
c
d

ecos@ubuntu:~$ cat > file2.txt
b
c
d
e

# using comm

ecos@ubuntu:~$ comm file1.txt file2.txt
a
		b
		c
		d
	e
ecos@ubuntu:~$ comm -12 file2.txt file2.txt
b
c
d

diff

ecos@ubuntu:~$ diff file1.txt file2.txt
1d0
< a
4a4
> e

ecos@ubuntu:~$ diff -c file1.txt file2.txt
*** file1.txt	2011-07-07 21:21:57.821292603 +0800
--- file2.txt	2011-07-07 21:22:08.585345976 +0800
***************
*** 1,4 ****
- a
  b
  c
  d
--- 1,4 ----
  b
  c
  d
+ e

ecos@ubuntu:~$ diff -u file1.txt file2.txt
--- file1.txt	2011-07-07 21:21:57.821292603 +0800
+++ file2.txt	2011-07-07 21:22:08.585345976 +0800
@@ -1,4 +1,4 @@
-a
 b
 c
 d
+e

ecos@ubuntu:~$ diff -Naur file1.txt file2.txt > patchfile.txt
ecos@ubuntu:~$ patch < patchfile.txt
patching file file1.txt
ecos@ubuntu:~$ cat file1.txt
b
c
d
e

tr

例子1

ecos@ubuntu:~$ echo "lowercase letters" | tr a-z A-Z
LOWERCASE LETTERS
例子2
ecos@ubuntu:~$ echo "lowercase letters" | tr [:lower:] A
AAAAAAAAA AAAAAAA

ecos@ubuntu:~$ echo "secret text" | tr a-zA-Z n-za-mN-ZA-M
frperg grkg
ecos@ubuntu:~$ echo "frperg grkg" | tr a-zA-Z n-za-mN-ZA-M
secret text
例子3
ecos@ubuntu:~$ echo "aaabbbccc" | tr -s ab
abccc

ecos@ubuntu:~$ echo "abcabcabc" | tr -s ab
abcabcabc

sed

例子

ecos@ubuntu:~$ echo "front" | sed 's/front/back/'
back

ecos@ubuntu:~$ echo "front" | sed 's_front_back_'
back

ecos@ubuntu:~$ echo "front" | sed '1s/front/back/'
back

ecos@ubuntu:~$ echo "front" | sed '2s/front/back/'
front

aspell

aspell check textfile
ecos@ubuntu:~$ cat > foo.txt
The quick brown fox jimped over the laxy dog.

ecos@ubuntu:~$ aspell check foo.txt

1) lax                                  6) Lexy
2) Lacy                                 7) Lay
3) lacy                                 8) lay
4) laxly                                9) Baxy
5) lazy                                 0) Maxy
i) Ignore                               I) Ignore all
r) Replace                              R) Replace all
a) Add                                  l) Add Lower
b) Abort                                x) Exit

?

第二十二章

在这一章中, 我们继续看文本相关的工具, 侧重于程序, 用于格式化文本输出,
而不是改变文本本身. 这些工具往往用于编写文字印刷的问题, 本章内容包括:
nl      - 数线
fold    - 包裹每一行指定长度
fmt     - 简单文本格式化
pr      - 准备文字印刷
printf  - 格式和打印数据输出
groff   - 文件格式系统

nl

Number Lines

例子

ecos@ubuntu:~$ cat 2011-07-20-03-10-58.033-VirtualBox-2948.log
Log created: 2011-07-20T03:10:58.339368000Z
Executable: /usr/lib/virtualbox/VirtualBox
Arg[0]: /usr/lib/virtualbox/VirtualBox
Arg[1]: --comment
Arg[2]: winxp
Arg[3]: --startvm
Arg[4]: 90091aec-563f-4871-887b-2ff997922d19
Arg[5]: --no-startvm-errormsgbox
fPIF=0 eip=ed6cf2b8

ecos@ubuntu:~$ nl 2011-07-20-03-10-58.033-VirtualBox-2948.log
     1	Log created: 2011-07-20T03:10:58.339368000Z
     2	Executable: /usr/lib/virtualbox/VirtualBox
     3	Arg[0]: /usr/lib/virtualbox/VirtualBox
     4	Arg[1]: --comment
     5	Arg[2]: winxp
     6	Arg[3]: --startvm
     7	Arg[4]: 90091aec-563f-4871-887b-2ff997922d19
     8	Arg[5]: --no-startvm-errormsgbox
     9	fPIF=0 eip=ed6cf2b8

ecos@ubuntu:~$ nl -n rz 2011-07-20-03-10-58.033-VirtualBox-2948.log
000001	Log created: 2011-07-20T03:10:58.339368000Z
000002	Executable: /usr/lib/virtualbox/VirtualBox
000003	Arg[0]: /usr/lib/virtualbox/VirtualBox
000004	Arg[1]: --comment
000005	Arg[2]: winxp
000006	Arg[3]: --startvm
000007	Arg[4]: 90091aec-563f-4871-887b-2ff997922d19
000008	Arg[5]: --no-startvm-errormsgbox
000009	fPIF=0 eip=ed6cf2b8

fold

Wrap Each Line To A Specified Length

例子

ecos@ubuntu:~$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12 -s
The quick
brown fox
jumped over
the lazy
dog.

fmt

A Simple Text Formatter

例子

ecos@ubuntu:~$ fmt -w 50 2011-07-20-03-10-58.033-VirtualBox-2948.log
Log created: 2011-07-20T03:10:58.339368000Z
Executable: /usr/lib/virtualbox/VirtualBox
Arg[0]: /usr/lib/virtualbox/VirtualBox Arg[1]:
--comment Arg[2]: winxp Arg[3]: --startvm Arg[4]:
90091aec-563f-4871-887b-2ff997922d19 Arg[5]:
--no-startvm-errormsgbox fPIF=0 eip=ed6cf2b8

ecos@ubuntu:~$ fmt -cw 50 2011-07-20-03-10-58.033-VirtualBox-2948.log
Log created: 2011-07-20T03:10:58.339368000Z
Executable: /usr/lib/virtualbox/VirtualBox
Arg[0]: /usr/lib/virtualbox/VirtualBox Arg[1]:
--comment Arg[2]: winxp Arg[3]: --startvm Arg[4]:
90091aec-563f-4871-887b-2ff997922d19 Arg[5]:
--no-startvm-errormsgbox fPIF=0 eip=ed6cf2b8
ecos@ubuntu:~/Downloads$ cat > fmt-code.txt
# This file contains code with comments.
# This line is a comment.
# Followed by another comment line.
# And another.
This, on the other hand, is a line of code.
And another line of code.
And another.

ecos@ubuntu:~/Downloads$ fmt -w 50 -p '# ' fmt-code.txt
# This file contains code with comments.
# This line is a comment.  Followed by another
# comment line.  And another.
This, on the other hand, is a line of code.
And another line of code.
And another.
ngage@ubuntu:~/Downloads$

pr

Format Text For Printing

例子

ecos@ubuntu:~/Downloads$ pr -l 15 -w 50 2011-07-20-03-10-58.033-VirtualBox-2948.log


2011-07-21 00:34 2011-07-20-03-10-58.033-VirtualBox-2948.log Page 1


Log created: 2011-07-20T03:10:58.339368000Z
Executable: /usr/lib/virtualbox/VirtualBox
Arg[0]: /usr/lib/virtualbox/VirtualBox
Arg[1]: --comment
Arg[2]: winxp







2011-07-21 00:34 2011-07-20-03-10-58.033-VirtualBox-2948.log Page 2


Arg[3]: --startvm
Arg[4]: 90091aec-563f-4871-887b-2ff997922d19
Arg[5]: --no-startvm-errormsgbox
fPIF=0 eip=ed6cf2b8






ecos@ubuntu:~/Downloads$

printf

Format And Print Data

例子

ecos@ubuntu:~$ printf "I formatted the string: %s\n" foo
I formatted the string: foo

ecos@ubuntu:~$ printf "I formatted '%s' as a string.\n" foo
I formatted 'foo' as astring.

ecos@ubuntu:~$ printf "I formatted '%s' as astring.\n" foo
I formatted 'foo' as a string.
Common printf Data Type Specifiers
Specifier Description
d Format a number as a signed decimal integer.
f Format and output a floating point number.
o Format an integer as an octal number. Format a number as a signed decimal integer.
s Format a string.
x Format an integer as a hexadecimal number using lowercase a-f where needed.
X Same as x but use upper case letters.
% Print a literal % symbol (i.e. specify “%%”)

例子

ecos@ubuntu:~$ printf "%d, %f, %o, %s, %x, %X\n" 380 380 380 380 380 380
380, 380.000000, 574, 380, 17c, 17C

ecos@ubuntu:~$ printf "%s\t%s\t%s\n" str1 str2 str3
str1    str2    str3

ecos@ubuntu:~$ printf "<html>\n\t<head>\n\t\t<title>%s</title>\n \t</head>\n\t<body>\n\t\t<p>%s</p>\n\t</body>\n</html>\n" "Page Title" "Page Content"
<html>
	<head>
		<title>Page Title</title>

	</head>
	<body>
		<p>Page Content</p>
	</body>
</html>

groff

上例子

ecos@ubuntu:~$ zcat /usr/share/man/man1/ls.1.gz | head
.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.35.
.TH LS "1" "February 2011" "GNU coreutils 8.5" "User Commands"
.SH NAME
ls \- list directory contents
.SH SYNOPSIS
.B ls
[\fIOPTION\fR]... [\fIFILE\fR]...
.SH DESCRIPTION
.\" Add any additional description here
.PP

ecos@ubuntu:~$ man ls | head
LS(1)                                                                       User Commands                                                                       LS(1)



NAME
       ls - list directory contents

SYNOPSIS
       ls [OPTION]... [FILE]...

ecos@ubuntu:~$ zcat /usr/share/man/man1/ls.1.gz | groff -mandoc -Tascii | head
LS(1)                            User Commands                           LS(1)



NNAAMMEE
       ls - list directory contents

SSYYNNOOPPSSIISS
       llss [_O_P_T_I_O_N]... [_F_I_L_E]...

ecos@ubuntu:~$ zcat /usr/share/man/man1/ls.1.gz | groff -mandoc | head
%!PS-Adobe-3.0
%%Creator: groff version 1.21
%%CreationDate: Thu Jul 21 00:55:21 2011
%%DocumentNeededResources: font Times-Roman
%%+ font Times-Bold
%%+ font Times-Italic
%%DocumentSuppliedResources: procset grops 1.21 0
%%Pages: 4
%%PageOrder: Ascend
%%DocumentMedia: Default 612 792 0 () ()

ecos@ubuntu:~$ zcat /usr/share/man/man1/ls.1.gz \ groff -mandoc > foo.ps

ecos@ubuntu:~$ ps2pdf foo.ps ls.pdf

第二十三章

We will discuss the following commands:
pr     - 转换为文本文件
lpr    - 文件打印
a2ps   - Format files for printing on a PostScript printer
lpstat - 显示打印机的状态信息
lpq    - 表明打印机队列状态
lprm   - 取消打印作业

例子

ecos@ubuntu:~$ zcat /usr/share/man/man1/ls.1.gz | nroff -man | cat -A | head
LS(1)                            User Commands                           LS(1)$
$
$
$
N^HNA^HAM^HME^HE$
       ls - list directory contents$
$
S^HSY^HYN^HNO^HOP^HPS^HSI^HIS^HS$
       l^Hls^Hs [_^HO_^HP_^HT_^HI_^HO_^HN]... [_^HF_^HI_^HL_^HE]...$
$

ecos@ubuntu:~$ ls /usr/bin | pr -3 -w 65 | head


2011-07-22 00:13                                           Page 1


[		      atrm		    bmtoa
2to3		      autoconf		    bogofilter
2to3-2.7	      autoheader	    bogofilter-bdb
7z		      autom4te		    bogolexer
7za		      automake		    bogolexer-bdb

ecos@ubuntu:~$ ls /usr/bin | pr -4 -w 90 -l 88 | lp -o page-left=36 -o cpi=12 -o lpi=8

ecos@ubuntu:~$ ls /usr/bin | pr -3 | lpr

ecos@ubuntu:~$ lpstat -a

ecos@ubuntu:~$ ls /usr/bin | pr -4 -w 90 -l 88 | lp -o page-left=36 -o cpi=12 -o lpi=8

ecos@ubuntu:~$ ls /usr/bin | pr -3 -t | a2ps -o ~/Desktop/ls.ps -L 66

ecos@ubuntu:~$ cancel 603
ecos@ubuntu:~$ lpq

第二十四章

Compiling Programs
编译程序
ecos@ubuntu:~$ which gcc
/usr/bin/gcc

Part 5 – Writing Shell Scripts

第二十五章

什么是shell脚本?

在最简单的术语, 一个shell脚本是一个包含一系列命令. shell读取该文件并执行命令, 好像他们已经进入了命令行执行.

shell是独特的, 因为它是一个强大的命令行接口系统和一个脚本语言解释器. 正如我们看到大部分的事情可以在命令行也可以在脚本执行.

我们已经涵盖了许多shell的特点, 但我们都集中在这些特征中最普遍的是直接在命令行. shell还提供了一套功能通常(但不总是)写作时使用的程序.

如何写一个脚本

成功地创建并运行一个脚本, 我们需要做三件事:

1. 写一个脚本. shell脚本是普通的文本文件. 所以我们需要一个文本编辑器编写.
   最好的文本编辑器提供语法高亮, 让我们看到一个彩色编码的元素的脚本.
   语法高亮将帮助我们发现某些种类的常见错误. 这里我们推荐 vim 、 emacs.

2. 使脚本执行. 该系统是相当挑剔不让任何文本文件被视为一个程序, 并有很好的理由!我们需要设置脚本文件的权限来允许执行.

3. 把脚本放到shell可以找到它的地方. shell自动搜索某些目录执行文件时, 没有明确指定路径名.
   最方便的做法我们可以把我们的脚本放在这些目录.

脚本的格式

#!/bin/bash
# This is our first script.
echo 'I love ShopEx!'

在命令行

ecos@ubuntu:~$ echo 'I love ShopEx!'    # 这里是一个注释
I love ShopEx!

ecos@ubuntu:~$ cat > mylove.sh
#!/bin/bash
# This is our first script.
echo 'I love ShopEx!'

可执行权限

下一步我们是让我们的脚本执行, 通常有权限设置脚本, 脚本可以执行755和700的脚本. 只有所有者可以执行. 请注意, 脚本必须是可读的, 以便执行.

ecos@ubuntu:~$ ls -l mylove.sh
-rw-r--r-- 1 ecos ecos 62 2011-07-27 13:36 mylove.sh

ecos@ubuntu:~$ chmod 755 mylove.sh  # 给他附上执行权限
ecos@ubuntu:~$ ls -l mylove.sh
-rwxr-xr-x 1 ecos ecos 62 2011-07-27 13:36 mylove.sh

脚本文件位置

权限设置完了, 我们现在可以执行脚本:

ecos@ubuntu:~$ ./mylove.sh
I love ShopEx!
为了让脚本运行, 我们必须在脚本的名称与一个明确的路径. 如果我们不, 我们将得到这个:
ecos@ubuntu:~$ mylove.sh
/bin/bash: mylove.sh: command not found
这是为什么?是什么使我们的脚本不同于其他程序?事实上, 我们的脚本它的位置问题.在12章, 我们讨论了路径环境变量及其对系统如何可执行程序. 综上所述, 系统搜索的目录列表每次需要找到一个可执行程序, 如果没有显式指定路径. 这是系统如何知道执行/bin/ls 当我们在命令行的时候. /bin 目录的一个目录, 自动搜索系统. 目录列表是在一个环境变量命名为路径. 路径变量包含一个以冒号分隔的目录列表搜索. 我们可以查看内容的路径:
ecos@ubuntu:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
在这里我们看到我们的目录清单. 如果我们的脚本是位于任何一个目录列表中, 我们的问题就迎刃而解了. 注意第一个目录列表,/bin/local/sbin. 大多数的发行版配置路径变量包含一本目录中的用户的家目录, 允许用户执行自己的计划.所以如果我们创建本目录和我们的脚本在它, 它就应该开始工作像其他节目:
ecos@ubuntu:~$ sudo mv bin/mylove.sh /usr/local/sbin/
ecos@ubuntu:~$ mylove.sh
I love ShopEx!
而它确实是这样的.

新手不要玩了.

如果路径变量不包含目录, 我们可以很容易地添加了包括这一行的. 我的是 bachrc 文件:

ecos@ubuntu:~$ export PATH=~/bin:"$PATH"
在这种变化是, 它将影响每一个新的终端会话. 更改应用到目前的终端会话, 我们必须有 shell 重读我的是 bachrc 的文件.

这可以通过“采购(sourcing)”:

ecos@ubuntu:~$ . .bachrc
点(.)命令的同义词的指挥, shell 体内置读取指定文件的命令, 把它像从键盘输入.
注:
ubuntu 自动加 ~/bin 目录路径变量, 如果当用户的 ~/bin 目录存在, 我的 bin 文件执行.
因此, 关於系统, 如果我们创建 ~/bin 目录, 然后重新登录, 全部工作.

脚本的最佳目录

Good Locations For Scripts
该 ~/bin 目录是把脚本为个人使用一个好地方. 如果我们写一个脚本, 每个系统可以使用, 传统的位置 /usr/local/bin .
脚本的使用由系统管理员通常位于 /usr/local/sbin . 在大多数情况下, 当地提供的软件, 或是否脚本编译的程序,
应放在 /usr/local 层次和不在 /bin /usr/bin. 这些目录是由指定的文件系统层次标准只包含文件提供和维持的分配器.

更多的组织技巧

一个关键目标, 严重的脚本创作是易于维护; 即, 容易在一个脚本可以由其作者或其他适应不断变化的需求被修改.

脚本容易阅读和理解的方式是一个方便的维护.

长选项名称

很多命令我们研究功能的短期和长期的选项名称. 例如, 该命令有许多选项, 可以表示在或长或短的形式. 比如说

ecos@ubuntu:~$ ls -ad
and:
ecos@ubuntu:~$ ls --all --directory
命令, 在利益的减少打字, 短选项优先进入选项在命令行上, 但当写脚本, 长选项可以提供更好的可读性.

第二十六章

开始一个项目

从这一章, 我们将开始建立一个程序. 这个项目的目的是看到各种 shell 的功能是用来创建程序和更重要的是创造良好的程序.

第一阶段

最小的文件

首先我们需要知道的是格式良好的文档. 它看起来像这样:

<HTML>
    <HEAD>
        <TITLE>Page Title</TITLE>
    </HEAD>
    <BODY>
        Page body.
    </BODY>
</HTML>

我们可以写一个程序, 这样做很容易. 让我们开始我们的文本编辑器, 并创建一个新文件名为 ~/usr/local/sbin/sys_info_page:
ecos@ubuntu:~$ echo $PTAH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

ecos@ubuntu:~$ sudo vim /usr/local/sbin/sys_info_page
#!/bin/bash

# Program to output a system information page

echo "<HTML>"
echo "  <HEAD>"
echo "      <TITLE>Page Title</TITLE>"
echo "  </HEAD>"
echo "  <BODY>"
echo "      Page body."
echo "  </BODY>"
echo "</HTML>"

ecos@ubuntu:~$ sys_info_page    # 没有权限
bash: /usr/local/sbin/sys_info_page: Permission denied

ecos@ubuntu:~$ sudo chmod 755 /usr/local/sbin/sys_info_page    # 赋予执行权限
ecos@ubuntu:~$ sys_info_page
<HTML>
   <HEAD>
      <TITLE>Page Title</TITLE>
   </HEAD>
   <BODY>
       Page body.
   </BODY>
</HTML>
在程序运行时, 我们应该看到文本文档的显示在屏幕上, 由于回波脚本命令将其输出到标准输出.

我们会重新运行程序和重定向程序的输出到 sys_info_page 页面, 这样我们可以查看结果与网页浏览器:

ecos@ubuntu:~$ sys_info_page > sys_info_page.html
ecos@ubuntu:~$ google-chrome sys_info_page.html
Created new window in existing browser session.
到目前为止还不错. 在编写程序时, 它力求简单和清晰总是一个好主意.

第二阶段
加点数据

现在, 我们的程序可以产生一个最小的文件, 让我们把一些报告中的数据. 为此, 我们将进行以下更改:

#!/bin/bash

# Program to output a system information page

echo "<HTML>
        <HEAD>
            <TITLE>System Information Report</TITLE>
        </HEAD>
        <BODY>
            <H1>System Information Report</H1>
        </BODY>
    </HTML>"
我们增加了一个页面标题和标题的报告主体.

变量和常量

我们的脚本有一个问题. 注意字符串“System Information Report”是重复?我们的小脚本, 它不是一个问题, 但让我们想象我们的脚本是很长的和我们有多个实例,这个字符串. 如果我们想改变的东西, 我们会改变它在多个地方, 这可能是很多工作.如果我们能安排脚本使字符串只出现了一次而不是多次?这将使未来维护脚本容易得多.这是我们如何做:

#!/bin/bash

# Program to output a system information page

title="System Information Report"

echo "<HTML>
        <HEAD>
            <TITLE>$title</TITLE>
        </HEAD>
        <BODY>
            <H1>$title</H1>
        </BODY>
</HTML>"
通过创建一个名为标题和分配给它的值“System Information Report”, 我们可以在多个位置的字符串用参数扩展.那么, 我们如何创建一个变量?简单, 我们只使用它. 当 shell 遇到一个变量, 它会自动创建它.这不同于许多编程语言中, 变量必须明确声明或定义使用前. shell 是非常宽松的, 这会导致一些问题.例如, 在命令行考虑这个场景:
ngage@ubuntu:~$ echo $foo

ngage@ubuntu:~$ foo="yes"
ngage@ubuntu:~$ echo $foo
yes
ngage@ubuntu:~$ echo $fool

ngage@ubuntu:~$
我们首先分配 foo 值为 "yes", echo foo 得到值.

下一步我们显示变量值的名字拼错为"fool", 得到了一个空白的结果.这是因为 shell 为 fool 赋值的事后遇到了它, 我们必须密切注意我们的拼写!它也是重要的是了解到底发生了什么, 在这个例子.从我们以往的研究如何在 shell 进行扩张, 我们知道, 命令:

ecos@ubuntu:~$ echo $foo
yes
ecos@ubuntu:~$ echo yes
yes
# 而命令:
ecos@ubuntu:~$ echo $fool

# 扩展到:
ecos@ubuntu:~$ echo
空变量扩展到什么!这会严重破坏的命令, 需要参数. 这里的一个例子:
ecos@ubuntu:~$ foo=foo.txt
ecos@ubuntu:~$ fool=fool.txt
ecos@ubuntu:~$ cp $foo $fool
cp: cannot stat `foo.txt': No such file or directory
我们将值赋给变量, foo 和 foo1 . 然后执行一个 cp, 但拼错名字的争论. 扩建后, 该命令只发送一个论点, 虽然它需要2.
有一些规则有关的变量名:

1. 变量名可以包含字母数字字符(字母和数字)和下划线字符.

2. 第一个字符的变量名必须是字母或下划线.

3. 空格和标点符号是不允许的.
“variable”意味着一种值的变化, 并在许多应用中, 变量是用这种方式. 然而, 在我们的应用程序中的变量, 是用来作为一个常数.恒定就像一个变量, 它有一个名字和包含一个值. 不同的是, 常量的值不会改变. 在一个应用程序进行几何计算, 我们可以定义为一个常数圆周率, 并分配给它的值为3.1415, 而不是使用一些在我们的程序上. 外壳没有区分变量和常量;他们大多为程序员方便. 一个共同的约定是使用大写字母和小写指定常数的变量. 我们将会修改脚本遵守本公约:
#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"

echo "<HTML>
        <HEAD>
            <TITLE>$TITLE</TITLE>
        </HEAD>
        <BODY>
            <H1>$TITLE</H1>
        </BODY>
</HTML>"

赋值给变量和常量

这里是我们的知识点. 正如我们所看到的, 这个变量赋值:

variable=value
在这里, 我们试图改变文件名从myfile到myfile1:
ecos@ubuntu:~$ filename="myfile"
ecos@ubuntu:~$ touch $filename
ecos@ubuntu:~$ mv $filename $filename1
mv: missing destination file operand after `myfile'
Try `mv --help' for more information.
尝试失败因为 shell 解释这个论点的机动命令作为一个新的(空)变量. 这个问题是可以克服这种方式:
ecos@ubuntu:~$ mv $filename ${filename}1
通过增加周边支架, shell 不再解释尾部1变量名.

我们将以此为契机在报告添加一些数据, 即日期和时间的报告和创建用户名的创造者:

#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"

echo "<HTML>
        <HEAD>
            <TITLE>$TITLE</TITLE>
        </HEAD>
        <BODY>
            <H1>$TITLE</H1>
            <P>$TIME_STAMP</P>
        </BODY>
</HTML>"
ecos@ubuntu:~$

Here Documents

很像php里面的语法:
command << token
text
token
phper你懂的.

现在我们可以把上面的例子修改下

#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"

cat << _EOF_
<HTML>
    <HEAD>
        <TITLE>$TITLE</TITLE>
    </HEAD>
    <BODY>
        <H1>$TITLE</H1>
        <P>$TIME_STAMP</P>
    </BODY>
</HTML>
_EOF_
这里还有例子
ecos@ubuntu:~$ foo="some text"
ecos@ubuntu:~$ cat << _EOF_
> $foo
> "$foo"
> '$foo'
> \$foo
> _EOF_
some text
"some text"
'some text'
$foo
我们可以看到 shell 不注意引号. 它把他们当作普通字符. 这使我们在这里自由地嵌入输出文件. 这可能是有用的报告程序.

这里的文件可以用任何命令, 接受标准输入. 在这个例子中, 我们使用一个文档在这里通过一系列命令的程序来检索文件从远程服务器:

#!/bin/bash

# Script to retrieve a file via FTP

FTP_SERVER=ftp.nl.debian.org
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
REMOTE_FILE=debian-cd_info.tar.gz

ftp -n << _EOF_
open $FTP_SERVER
user anonymous me@linuxbox
cd $FTP_PATH
hash
get $REMOTE_FILE
bye
_EOF_
ls -l $REMOTE_FILE
如果我们改变重定向操作符从“<<”, “<<”, 外壳会忽略领导人物在这里文件标签. 这允许在文件缩进, 以提高可读性:
#!/bin/bash

# Script to retrieve a file via FTP

FTP_SERVER=ftp.nl.debian.org
FTP_PATH=/debian/dists/lenny/main/installer-i386/current/images/cdrom
REMOTE_FILE=debian-cd_info.tar.gz
ftp -n <<- _EOF_
    open $FTP_SERVER
    user anonymous me@linuxbox
    cd $FTP_PATH
    hash
    get $REMOTE_FILE
    bye
    _EOF_

ls -l $REMOTE_FILE
总结
在这一章中, 我们开始了一个项目, 我们会通过的过程中建立一个成功的剧本. 我们介绍的概念, 变量和常量, 以及他们如何可以用来. 他们是第一个应用, 我们会发现许多参数扩展. 我们也期待在如何产生输出从我们的脚本, 和各种方法嵌入文本块.

第二十七章

自顶向下设计

作为项目获得更大和更复杂的, 他们变得更难设计, 代码和维护. 如同任何大型项目, 它往往是一个好主意打破大型, 复杂的任务分成一系列的小, 简单的任务.让我们想象一下, 我们试图描述一个共同的, 日常的任务, 去市场买菜, 一个人从火星. 我们可以描述整个过程如下一系列步骤:

  1. 在汽车里
  2. 去市场
  3. 公园
  4. 进入市场
  5. 购买食物
  6. 回到车里
  7. 开车回家
  8. 公园
  9. 进入房子

然而, 一个人从火星可能需要更多的细节. 我们可以进一步分解成子任务“公园”这一系列步骤:

  1. 找到停车位
  2. 驱车进入太空
  3. 关闭发动机
  4. 设置停车制动
  5. 下车
  6. 锁车

“关闭”任务可以进一步细分为步骤包括“关闭点火开关, “取下点火钥匙”等, 直到每一步的整个过程中会得到了市场的充分定义.这一过程中确定了顶级的步骤和发展越来越详细的意见, 这些步骤叫做自顶向下设计.这项技术使我们能够打破大型复杂的任务, 为许多小的, 简单的任务. 自顶向下的设计是一种常见的方法, 设计程序和一个非常适合编程的特别.

在这一章中, 我们将使用自顶向下设计的进一步发展我们的报告生成的脚本.

shell 的功能

  1. 我们的脚本目前执行以下步骤生成的文件
  2. 打开页面
  3. 打开页面标题
  4. 设置页面标题
  5. 页面的标题
  6. 打开页面的主体
  7. 输出页面标题
  8. 输出时间戳
  9. 页面的身体
  10. 关闭页面

为我们的下一个阶段的发展, 我们会添加一些额外的任务之间的步骤7和8. 这将包括:

    • 系统正常运行时间和负载. 这是大量的时间自上次关机或重新启动和平均人数任务目前的处理器上运行的几个时间间隔.
    • 磁盘空间. 整体空间的使用该系统的存储设备.
    • 家居空间. 存储空间量是由每个用户使用.

如果我们为每一个这些任务有一个命令, , 我们可以添加到我们的脚本通过一个简单的命令替换:

#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"

cat << _EOF_
<HTML>
    <HEAD>
        <TITLE>$TITLE</TITLE>
    </HEAD>
    <BODY>
        <H1>$TITLE</H1>
        <P>$TIME_STAMP</P>
        $(report_uptime)
        $(report_disk_space)
        $(report_home_space)
    </BODY>
</HTML>
_EOF_
我们可以创建这些额外的命令的方法. 我们可以在一个目录写三个独立的脚本, 或者我们可以在程序中嵌入脚本为 shell 的功能.正如我们之前提到的, shell 的功能是“小脚本”, 位于内其他脚本和可作为自治计划. shell 的功能有两只句法形式:
function name {
    commands
    return
)
and
name () {
    commands
    return
}

其中名称是名称的函数和命令是一个命令序列中包含的功能.

两种形式是相同的, 可以互换使用. 下面我们看一个脚本, 显示了一个shell的功能:

#!/bin/bash

# Shell function demo

function funct {
    echo "Step 2"
    return
}

# Main program starts here

echo "Step 1"
funct
echo "Step 3"

我们会添加最小 shell 函数定义的脚本:

#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"

report_uptime () {
    return
}
report_disk_space () {
    return
}
report_home_space () {
    return
}

cat << _EOF_
<HTML>
    <HEAD>
        <TITLE>$TITLE</TITLE>
    </HEAD>
    <BODY>
        <H1>$TITLE</H1>
        <P>$TIME_STAMP</P>
        $(report_uptime)
        $(report_disk_space)
        $(report_home_space)
    </BODY>
</HTML>
_EOF_
shell 函数名称遵循相同的规则变量. 一个函数必须包含至少一个命令. 返回命令(这是可选的)满足要求.

局部变量

在脚本里, 我们写了到目前为止, 所有的变量(包括常量)已全局变量. 全局变量维持其生存的整个程序.这是罚款, 许多事情, 但是它有时复杂使用函数. shell的功能, 它通常是可取的局部变量. 局部变量只在函数在定义它们的shell停止存在, 一旦shell功能终止.具有局部变量允许程序员使用变量的名字可能已经存在, 无论是在全球还是在其他外壳脚本功能, 而不必担心潜在的冲突.

这里是一个脚本示例演示如何定义和使用局部变量:

#!/bin/bash

# local-vars: script to demonstrate local variables

foo=0 # global variable foo

funct_1 () {
    local foo # variable foo local to funct_1

    foo=1
    echo "funct_1: foo = $foo"
}


funct_2 () {
    local foo # variable foo local to funct_2

    foo=2
    echo "funct_2: foo = $foo"
}


echo "global: foo = $foo"
funct_1
echo "global: foo = $foo"
funct_2
echo "global: foo = $foo"
外部的shell功能启动一次, 变量不再存在. 当我们运行这个脚本, 我们看到的结果:
ecos@ubuntu:~$ local-vars
global:  foo = 0
funct_1: foo = 1
global:  foo = 0
funct_2: foo = 2
global:  foo = 0
例子
ecos@ubuntu:~$ cat > s1.sh
#!/bin/bash

# Program to output a system information page

TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"

#report_uptime () {
#    echo "Function report_uptime executed."
#    return
#}
#report_disk_space () {
#    echo "Function report_disk_space executed."
#    return
#}
#report_home_space () {
#    echo "Function report_home_space executed."
#    return
#}

cat << _EOF_
<HTML>
    <HEAD>
        <TITLE>$TITLE</TITLE>
    </HEAD>
    <BODY>
        <H1>$TITLE</H1>
        <P>$TIME_STAMP</P>
        $(report_uptime)
        $(report_disk_space)
        $(report_home_space)
    </BODY>
</HTML>
_EOF_
ecos@ubuntu:~$ chmod 755 s1.sh
ecos@ubuntu:~$ ./s1.sh
<HTML>
        <HEAD>
            <TITLE>System Information Report For ubuntu</TITLE>
        </HEAD>
        <BODY>
            <H1>System Information Report For ubuntu</H1>
            <P>Generated 07/27/2011 06:16:18 PM CST, by ngage</P>



        </BODY>
</HTML>

在 s1.sh 文件中打开以下内容
report_uptime () {
    echo "Function report_uptime executed."
    return
}
report_disk_space () {
    echo "Function report_disk_space executed."
    return
}
report_home_space () {
    echo "Function report_home_space executed."
    return
}
然后在执行一次 s1.sh 脚本
ecos@ubuntu:~$ ./s1.sh
<HTML>
        <HEAD>
            <TITLE>System Information Report For ubuntu</TITLE>
        </HEAD>
        <BODY>
            <H1>System Information Report For ubuntu</H1>
            <P>Generated 07/27/2011 06:30:15 PM CST, by ngage</P>
            Function report_uptime executed.
            Function report_disk_space executed.
            Function report_home_space executed.
        </BODY>
</HTML>
我们现在看到的, 事实上, 我们正在执行三功能.

# 我们的功能框架到位和工作, 它的时间来充实一些功能代码. 第一, report_uptime() 功能:
report_uptime () {
    cat <<- _EOF_
        <H2>System Uptime</H2>
        <PRE>$(uptime)</PRE>
_EOF_
return
}

# 这是很简单的. 我们使用这文件输出部分和输出的运行命令, 包围<PRE>标签保存格式的命令. report_disk_space() 功能类似:
report_disk_space () {
    cat <<- _EOF_
        <H2>Disk Space Utilization</H2>
        <PRE>$(df -h)</PRE>
_EOF_
    return
}

# 这个函数使用 df -h 命令确定的磁盘空间. 最后, 我们将修改 report_home_space() 功能:
report_home_space () {
    cat <<- _EOF_
        <H2>Home Space Utilization</H2>
        <PRE>$(ls ~)</PRE>
_EOF_
    return
}

执行之后

ecos@ubuntu:~$ ./s1.sh > s1.html
ecos@ubuntu:~$ firefox s1.html
Created new window in existing browser session.

第二十八章

流量控制: if分支

if

利用shell我们可以逻辑代码

x=5
if [ $x = 5 ]; then
    echo "x equals 5."
else
    echo "x does not equal 5."
fi
首先我们在命令行里实现它
ecos@ubuntu:~$ x=5
ecos@ubuntu:~$ if [ $x = 5 ]; then echo "yes"; else echo "no"; fi
yes
ecos@ubuntu:~$ x=55
ecos@ubuntu:~$ if [ $x = 5 ]; then echo "yes"; else echo "no"; fi
no
The if statement has the following syntax:
if commands; then
    commands
[elif commands; then
    commands...]
[else
    commands]
fi

Exit Status

退出状态

命令(我们写包括 script 和 shell 的功能)系统赋值的时候, 终止, 叫做退出状态(Exit Status). 这个值是一个整数, 范围在0到255, 表明成功或失败的命令的执行.按照惯例, 一个值为零表示成功, 任何其他值表示失败. shell 提供了一个参数, 我们可以使用审查的退出状态. 在这里, 我们看到它在行动:

ecos@ubuntu:~$ ls -d /usr/bin
/usr/bin
ecos@ubuntu:~$ echo $?
0
ecos@ubuntu:~$ ls -d /bin/usr
ls: cannot access /bin/usr: No such file or directory
ecos@ubuntu:~$ echo $?
2
在这个例子中, 我们执行两次命令. 第一时间, 命令执行成功. 如果我们显示参数的值为?, 我们看到, 它是0.我们执行的命令一次, 产生一个错误检查参数$?又来了. 这个时候, 它包含了2, 表明该命令时遇到错误.一些命令使用不同的退出状态值提供诊断错误, 而许多命令只是退出值时失败. 人的网页通常包括一节题为“退出状态, ”说明什么码的使用. 然而, 0表示成功.

shell提供非常简单的内建命令都终止与0或一个退出状态. 真正的命令都成功执行和假命令始终执行失败:

ecos@ubuntu:~$ true
ecos@ubuntu:~$ echo $?
0
ecos@ubuntu:~$ false
ecos@ubuntu:~$ echo $?
1
我们可以利用这些命令, 看看如果声明的作品. 如果真的是什么评估成功或失败的命令:
ecos@ubuntu:~$ if true; then echo "It's true."; fi
It's true.
ecos@ubuntu:~$ if false; then echo "It's true."; fi
ecos@ubuntu:~$
如果命令列表如下, 最后的命令列表中的评价:
ecos@ubuntu:~$ if false; true; then echo "It's true."; fi
It's true.
ecos@ubuntu:~$ if true; false; then echo "It's true."; fi
ecos@ubuntu:~$

test

到目前为止, 最常用的命令, if is test . test命令执行各种检查和比较. 它有2个等价形式:

test expression
and the more popular:
[ expression ]

File Expressions
文件表达式

下面的公式来评估文件的状态:

test File Expressions
Expression Is True If:
file1 -ef file2 file1 and file2 have the same inode numbers (the two filenames refer to the same file by hard linking).
file1 -nt file2 file1 is newer than file2.
file1 -ot file2 file1 is older than file2.
-b file file exists and is a block special (device) file.
-c file file exists and is a character special (device) file.
-d file file exists and is a directory.
-e file file exists.
-f file file exists and is a regular file.
-g file file exists and is set-group-ID.
-G file file exists and is owned by the effective group ID.
-k file file exists and has its “sticky bit” set.
-L file file exists and is a symbolic link.
-O file file exists and is owned by the effective user ID.
-p file file exists and is a named pipe.
-r file file exists and is readable (has readable permission for the effective user).
-s file file exists and has a length greater than zero.
-S file file exists and is a network socket.
-t fd fd is a file descriptor directed to/from the terminal. This can be used to determine whether standard input/output/ error is being redirected.
-u file file exists and is setuid.
-w file file exists and is writable (has write permission for the effective user).
-x file file exists and is executable (has execute/search permission for the effective user).

在这里, 我们有一个脚本演示了一些 expression:

ecos@ubuntu:~$ cat test.sh
#!/bin/bash

# test-file: Evaluate the status of a file

FILE=~/.bashrc

if [ -e "$FILE" ]; then
    if [ -f "$FILE" ]; then
        echo "$FILE is a regular file."
    fi
    if [ -d "$FILE" ]; then
        echo "$FILE is a directory."
    fi
    if [ -r "$FILE" ]; then
        echo "$FILE is readable."
    fi
    if [ -w "$FILE" ]; then
        echo "$FILE is writable."
    fi
    if [ -x "$FILE" ]; then
        echo "$FILE is executable/searchable."
    fi
else
    echo "$FILE does not exist"
    exit 1
fi

exit
[结束 ctrl+d]
ecos@ubuntu:~$ chmod 755 test.sh
ecos@ubuntu:~$ ./test.sh
/home/ngage/.bashrc is a regular file.
/home/ngage/.bashrc is readable.
/home/ngage/.bashrc is writable.
ecos@ubuntu:~$

String Expressions
字符串表达式
Expression Is True If...
string string is not null.
-n string The length of string is greater than zero.
-z string The length of string is zero.
string1 = string2 string1 == string2 string1 and string2 are equal. Single or double equal signs may be used, but the use of double equal signs is greatly preferred.
string1 != string2 string1 and string2 are not equal.
string1 > string2 string1 sorts after string2.
string1 < string2 string1 sorts before string2.

这里是一个包含字符串表达式的脚本:

ecos@ubuntu:~$ cat > string.sh
#!/bin/bash

# test-string: evaluate the value of a string

ANSWER=maybe

if [ -z "$ANSWER" ]; then
    echo "There is no answer." >&2
    exit 1
fi
if [ "$ANSWER" = "yes" ]; then
    echo "The answer is YES."
elif [ "$ANSWER" = "no" ]; then
    echo "The answer is NO."
elif [ "$ANSWER" = "maybe" ]; then
    echo "The answer is MAYBE."
else
    echo "The answer is UNKNOWN."
fi
[结束 ctrl+d]
ecos@ubuntu:~$ chmod 755 string.sh
ecos@ubuntu:~$ ./string.sh
The answer is MAYBE.
ecos@ubuntu:~$

Integer Expressions
整数表达式

test Integer Expressions

Expression Is True If...
integer1 -eq integer2 integer1 is equal to integer2.
integer1 -ne integer2 integer1 is not equal to integer2.
integer1 -le integer2 integer1 is less than or equal to integer2.
integer1 -lt integer2 integer1 is less than integer2.
integer1 -ge integer2 integer1 is greater than or equal to integer2.
integer1 -gt integer2 integer1 is greater than integer2.

一个有趣的脚本: 如何确定整数是否为偶数或奇数.

ngage@ubuntu:~$ cat > int.sh
#!/bin/bash

# test-integer: evaluate the value of an integer.

INT=-5

if [ -z "$INT" ]; then
    echo "INT is empty." >&2
    exit 1
fi
if [ $INT -eq 0 ]; then
    echo "INT is zero."
else
    if [ $INT -lt 0 ]; then
        echo "INT is negative."
    else
        echo "INT is positive."
    fi
    if [ $((INT % 2)) -eq 0 ]; then
        echo "INT is even."
    else
        echo "INT is odd."
    fi
fi
[结束 ctrl+d]
ngage@ubuntu:~$ chmod 755 int.sh
ngage@ubuntu:~$ ./int.sh
INT is negative.
INT is odd.

A More Modern Version Of test
一个现代版的测试

新版本的 bash 包括正则命令充当增强置换试验. 它使用下面的语法:

[[ expression ]]
脚本
#!/bin/bash

# test-integer2: evaluate the value of an integer.

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [ $INT -eq 0 ]; then
        echo "INT is zero."
    else
    if [ $INT -lt 0 ]; then
        echo "INT is negative."
    else
        echo "INT is positive."
    fi
    if [ $((INT % 2)) -eq 0 ]; then
        echo "INT is even."
    else
        echo "INT is odd."
    fi
fi
else
    echo "INT is not an integer." >&2
    exit 1
fi
运用正则表达式, 我们能够限制值的字符串开始只有一个可选减号, 后面跟着一个或多个数. 这个表达也消除了可能的空值.另一个特点是, [[]]==操作符支持模式匹配相同的路径扩展. 比如
ecos@ubuntu:~$ FILE=foo.bar
ecos@ubuntu:~$ if [[ $FILE == foo.* ]]; then
> echo "$FILE matches pattern 'foo.*'"
> fi
foo.bar matches pattern 'foo.*'
This makes [[ ]] useful for evaluating file and path names.

(( )) - Designed For Integers

演示

ecos@ubuntu:~$ if ((1)); then echo "It is true."; fi
It is true.
ecos@ubuntu:~$ if ((0)); then echo "It is true."; fi
ecos@ubuntu:~$
使用(()), 我们可以稍微简化这样的 test-integer2 脚本:
#!/bin/bash

# test-integer2a: evaluate the value of an integer.

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if ((INT == 0)); then
        echo "INT is zero."
    else
        if ((INT < 0)); then
            echo "INT is negative."
        else
            echo "INT is positive."
        fi
        if (( ((INT % 2)) == 0)); then
            echo "INT is even."
        else
            echo "INT is odd."
        fi
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

Combining Expressions
结合表达式

Logical Operators

Operation test [[ ]] and (( ))
AND -a &&
OR -o ||
NOT ! !

#!/bin/bash

# test-integer3: determine if an integer is within a
# specified range of values.

MIN_VAL=1
MAX_VAL=100

INT=50

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [[ INT -ge MIN_VAL && INT -le MAX_VAL ]]; then
        echo "$INT is within $MIN_VAL to $MAX_VAL."
    else
        echo "$INT is out of range."
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

在这个脚本中, 我们确定的整数INT值之间的MIN_VAL和MAX_VAL价值在于,这是由[[]]一次性使用, 其中包括由&&操作符分隔两个表达式执行的, 我们也可以这样编码使用测试:

if [ $INT -ge $MIN_VAL -a $INT -le $MAX_VAL ]; then
    echo "$INT is within $MIN_VAL to $MAX_VAL."
else
    echo "$INT is out of range."
fi
该!否定经营者颠倒了一个表达式的结果, 它返回true, 如果表达式是假的, 它返回false,如果表达式为真, 在下面的脚本, 我们修改了我们的评价逻辑找到INT值外指定范围:
#!/bin/bash

# test-integer4: determine if an integer is outside a
# specified range of values.

MIN_VAL=1
MAX_VAL=100
INT=50

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [[ ! (INT -ge MIN_VAL && INT -le MAX_VAL) ]]; then
        echo "$INT is outside $MIN_VAL to $MAX_VAL."
    else
        echo "$INT is in range."
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi
我们还包括周围的括号表达式进行分组, 如果这些人不包括在内, 否定只适用于第一个表达式, 而不是两者的结合编码与测试这将是这样做的方式
if [ ! \( $INT -ge $MIN_VAL -a $INT -le $MAX_VAL \) ]; then
    echo "$INT is outside $MIN_VAL to $MAX_VAL."
else
    echo "$INT is in range."
fi
由于测试用的所有表达式和运营商都作为命令的参数处理, shell(不像[]和(())), 有特殊意义的bash的字符, 比如<, >, (and), 必须引用或转义.眼看测试[]做的事情大致相同, 这是可取的吗?测试是传统的(和POSIX的一部分), 而[[]]具体到bash.重要的是要知道如何使用测试, 因为它是非常广泛的使用, 但[]显然更有价值和更容易编码.

Control Operators: Another Way To Branch

控制运算符:另一种分支
command1 && command2
command1 || command2

例子

ecos@ubuntu:~$ mkdir temp && cd temp
ecos@ubuntu:~$ [ -d temp ] || mkdir temp

第二十九章

Reading Keyboard Input
#!/bin/bash

# test-integer2: evaluate the value of an integer.

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [ $INT -eq 0 ]; then
        echo "INT is zero."
    else
    if [ $INT -lt 0 ]; then
        echo "INT is negative."
    else
        echo "INT is positive."
    fi
    if [ $((INT % 2)) -eq 0 ]; then
        echo "INT is even."
    else
        echo "INT is odd."
    fi
fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

read

Read Values From Standard Input
read [-options] [variable...]

例子

#!/bin/bash

# read-integer: evaluate the value of an integer.

echo -n "Please enter an integer -> "
read int

if [[ "$int" =~ ^-?[0-9]+$ ]]; then
    if [ $int -eq 0 ]; then
        echo "$int is zero."
    else
        if [ $int -lt 0 ]; then
            echo "$int is negative."
        else
            echo "$int is positive."
        fi
        if [ $((int % 2)) -eq 0 ]; then
            echo "$int is even."
        else
            echo "$int is odd."
        fi
    fi
else
    echo "Input value is not an integer." >&2
    exit 1
fi
我们用- n选项(抑制输出换行符)echo来显示一个提示, 然后使用读取输入一个变量int值. 运行这个脚本的结果:
ecos@ubuntu:~$ read-interger.sh
Please enter an integer -> 5
5 is positive.
5 is odd.
阅读可以将输入多个变量, 在这个脚本中所示:
#!/bin/bash

# read-multiple: read multiple values from keyboard

echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5

echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"
在这个脚本中, 我们分配和显示多达五个值. 请注意如何读取时的行为给予不同的值:
ecos@ubuntu:~$ read-multiple.sh
Enter one or more values > a b c d e
var1 = 'a'
var2 = 'b'
var3 = 'c'
var4 = 'd'
var5 = 'e'
如果读收到比预期的数量少, 额外的变量是空的, 而在最后一个变量的过量输入结果包含所有的额外的输入.

如果没有变量的读取命令后上市, 一个shell变量, REPLY, 将被分配所有的输入:

#!/bin/bash
# read-single: read multiple values into default variable

echo -n "Enter one or more values > "
read

echo "REPLY = '$REPLY'"
运行这个脚本:
ecos@ubuntu:~$ read-single.sh
Enter one or more values > S h o p E x
REPLY = 'S h o p E x'

Options

read 支持一下选项:

read Options

Option Description
-a array Assign the input to array, starting with index zero. We will cover arrays in Chapter 36.
-d delimiter The first character in the string delimiter is used to indicate end of input, rather than a newline character.
-e Use Readline to handle input. This permits input editing in the same manner as the command line.
-n num Read num characters of input, rather than an entire line.
-p prompt Display a prompt for input using the string prompt.
-r Raw mode. Do not interpret backslash characters as escapes.
-s Silent mode. Do not echo characters to the display as they are typed. This is useful when inputting passwords and other confidential information.
-t seconds Timeout. Terminate input after seconds. read returns a non-zero exit status if an input times out.
-u fd Use input from file descriptor fd, rather than standard input.

使用不同的选项, 我们可以做读有趣的事情. 例如, 使用 -p选项, 我们可以提供一个及时的的字符串:

#!/bin/bash

# read-single: read multiple values into default variable

read -p "Enter one or more values > "

echo "REPLY = '$REPLY'"
使用 -t 和 -s 选项, 我们可以编写一个脚本, 上面写着“secret(秘密)”的输入和超时, 如果输入的是没有在规定时间内完成
#!/bin/bash

# read-secret: input a secret pass phrase

if read -t 10 -sp "Enter secret pass phrase > " secret_pass; then
    echo -e "\nSecret pass phrase = '$secret_pass'"
else
    echo -e "\nInput timed out" >&2
    exit 1
fi
脚本会提示用户一个秘密通行短语, 并等待输入十秒钟. 如果该项目是没有在规定时间内完成, 该脚本将退出一个错误.由于包含了 -s 选项, 密码短语的字符不显示所键入的呼应.

IFS

通常情况下, 外壳上执行读取输入单词分割. 正如我们所看到的的, 这意味着, 由一个或多个空格成为单独的项目, 在输入行分隔的多个单词, 并通过读取分配给单独的变量.这种行为是一个shell变量配置名为IFS(内部域分隔符). IFS默认值包含空格, 制表符和换行符, 其中每个项目将彼此分开.我们可以调整IFS值控制领域的输入分离阅读. 例如, 在 /etc/passwd 文件中包含冒号字符作为字段分隔符使用的数据线.通过改变IFS值单个冒号, 我们可以使用读取输入的/ etc/ passwd和不同的变量, 成功地单独领域的内容. 在这里, 我们有一个脚本, 它只是:

#!/bin/bash

# read-ifs: read fields from a file

FILE=/etc/passwd

read -p "Enter a user name > " user_name

file_info=$(grep "^$user_name:" $FILE)

if [ -n "$file_info" ]; then
    IFS=":" read user pw uid gid name home shell <<< "$file_info"
    echo "User = '$user'"
    echo "UID = '$uid'"
    echo "GID = '$gid'"
    echo "Full Name = '$name'"
    echo "Home Dir. = '$home'"
    echo "Shell = '$shell'"
else
    echo "No such user '$user_name'" >&2
exit 1
fi
这个脚本提示用户输入的系统上的帐户的用户名, 然后显示在用户的记录在/ etc/ passwd文件中发现的不同领域. 脚本中包含了两个有趣的命令. 首先是:
file_info=$(grep "^$user_name:" $FILE)
此行分配grep命令的结果变量 file_info. 通过grep使用正则表达式, 保证了用户名, 将只匹配一个单一的 /etc/passwd 文件.

第二个有趣的命令是:

IFS=":" read user pw uid gid name home shell <<< "$file_info"
该命令由三部分组成:一个变量赋值, 与作为参数的变量名列表读取命令, 和一个陌生的重定向操作符. 我们来看看第一个变量赋值.

shell允许一个或多个变量赋值命令之前立即发生. 这些任务改变为如下的命令环境. 分配的影响是暂时的, 只有不断变化的环境命令的时间. 在我们的例子中, IFS的值更改为一个冒号字符. 另外, 我们可以有编码这种方式:

OLD_IFS="$IFS"
IFS=":"
read user pw uid gid name home shell <<< "$file_info"
IFS="$OLD_IFS"
存储在其中的IFS值, 指定一个新值, 执行读命令, 然后恢复IFS到其原始值. 显然, 放置在前面的命令的变量赋值的是一个更简洁的方式做同样的事情.

<<<操作符, 表示这里的字符串. 这里的字符串是像这里的文件, 只有较短的一个单一的字符串组成.在我们的例子中, 从 /etc/passwd 文件中的数据被送入读命令的标准输入. 我们可能会问, 为什么而斜的方法而不是选择:

echo "$file_info" | IFS=":" read user pw uid gid name home shell
你好了, 有一个原因...

你可以不使用读的管道

虽然read命令通常需要从标准输入的输入, 你不能做到这一点:

echo 'foo' | read
我们期望这项工作, 但事实并非如此. 该命令将显示成功, 但答复变量将永远是空的. 这是为什么? 解释已经做的shell处理管道与方式.

在bash(和其他shells如sh), 管道创建子shell. 这是shell和它的环境, 这是用来执行命令在管道的副本.

在我们上面的例子中, 读的是在一个子shell执行. 在类Unix系统的子shell进程创建环境的副本使用, 而他们执行.

当过程完成后, 被破坏环境的副本. 这意味着, 一个子shell中永远不能改变它的父进程的环境. 读分配给变量, 然后成为环境的一部分.

在上面的例子, 阅读价值的“foo”在其子shell的环境变量REPLY分配, 但是当命令退出, 子shell和它的环境被破坏, 丢失和分配的影响.

这里使用的字符串, 是解决此问题的途径之一. 另一种方法是会在后面的章节讨论.

Validating Input
验证输入

随着我们新的能力, 有键盘输入一个额外的编程挑战, 验证输入. 很多时候, 一个精心编写的程序和写得不好之间的差异是在程序的能力, 处理意外.通常情况下, 意外出现在错误的输入形式. 我们已经做了我们在前一章中, 我们检查的整数的值的一个评价方案这一点, 并筛选出空值和非数字字符.重要的是要执行这些类型的编程检查每一个程序接收输入, 防止无效数据的时间. 由多个用户共享的方案, 这一点尤为重要.省略这些保障在经济利益可能会原谅, 如果一个程序是用于执行某些特殊任务的作者的一次, 况且. 即使这样, 如果程序执行危险的任务, 如删除文件, 它会是明智的, 包括数据验证, 以防万一.

这里有一个验证各种输入的例子

#!/bin/bash

# read-validate: validate input
invalid_input () {
    echo "Invalid input '$REPLY'" >&2
    exit 1
}

read -p "Enter a single item > "

# input is empty (invalid)
[[ -z $REPLY ]] && invalid_input

# input is multiple items (invalid)
(( $(echo $REPLY | wc -w) > 1 )) && invalid_input

# is input a valid filename?
if [[ $REPLY =~ ^[-[:alnum:]\._]+$ ]]; then
    echo "'$REPLY' is a valid filename."
    if [[ -e $REPLY ]]; then
        echo "And file '$REPLY' exists."
    else
        echo "However, file '$REPLY' does not exist."
    fi

    # is input a floating point number?
    if [[ $REPLY =~ ^-?[[:digit:]]*\.[[:digit:]]+$ ]]; then
        echo "'$REPLY' is a floating point number."
    else
        echo "'$REPLY' is not a floating point number."
    fi

    # is input an integer?
    if [[ $REPLY =~ ^-?[[:digit:]]+$ ]]; then
        echo "'$REPLY' is an integer."
    else
            echo "'$REPLY' is not an integer."
    fi
else
    echo "The string '$REPLY' is not a valid filename."
fi
这个脚本提示用户输入一个项目. 该项目是事后分析, 以确定其内容.我们可以看到, 脚本使得很多的, 我们已经覆盖迄今概念, 包括shell函数, [], (()), 控制操作符&&, 和if, 以及一个适当的使用正则表达式

Menus
菜单

常见的类型是所谓的互动菜单驱动. 在菜单驱动的程序, 用户是一个选择列表, 并要求选择一个. 例如, 我们可以设想, 提出了以下程序:

Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit

Enter selection [0-3] >
使用我们编写我们的 sys_info_page 程序学到了什么, 我们可以构造一个菜单驱动式程序, 执行上述菜单上任务:
#!/bin/bash

# read-menu: a menu driven system information program

clear
echo "
Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"
read -p "Enter selection [0-3] > "

if [[ $REPLY =~ ^[0-3]$ ]]; then
    if [[ $REPLY == 0 ]]; then
        echo "Program terminated."
        exit
    fi
    if [[ $REPLY == 1 ]]; then
        echo "Hostname: $HOSTNAME"
        uptime
        exit
    fi
    if [[ $REPLY == 2 ]]; then
        df -h
        exit
    fi
    if [[ $REPLY == 3 ]]; then
        if [[ $(id -u) -eq 0 ]]; then
            echo "Home Space Utilization (All Users)"
            du -sh /home/*
        else
            echo "Home Space Utilization ($USER)"
            du -sh $HOME
        fi
        else
    fi
fi
exit
    echo "Invalid entry." >&2
    exit 1
fi
这个脚本是逻辑上分为两部分.
  • 第一部分显示的菜单, 并输入从用户的反应.
  • 第二部分标识的响应, 并进行选择的动作. 请注意在这个脚本中使用exit命令.

在这里它是用来防止脚本执行后的行动已进行了不必要的代码. 但它在这个脚本在程序中存在多个退出点通常是一个坏主意(它使程序逻辑很难理解).

Flow Control: Looping With while / until

Looping

while
#!/bin/bash

# while-count: display a series of numbers

count=1

while [ $count -le 5 ]; do
    echo $count
    count=$((count + 1))
done
echo "Finished."

执行结果

ecos@ubuntu:~$ while-count.sh
1
2
3
4
5
Finished.
while 命令的语法是
while commands; do commands; done
我们可以用一个while循环来提高从前面的章节读菜单程序:
#!/bin/bash

# while: a menu driven system information program

DELAY=3 # Number of seconds to display results

while [[ $REPLY != 0 ]]; do
    clear
    echo "
    Please Select:

    1. Display System Information
    2. Display Disk Space
    3. Display Home Space Utilization
    0. Quit
    "
    read -p "Enter selection [0-3] > "

    if [[ $REPLY =~ ^[0-3]$ ]]; then
        if [[ $REPLY == 0 ]]; then
            echo "Program terminated."
            sleep $DELAY
        fi
        if [[ $REPLY == 1 ]]; then
            echo "Hostname: $HOSTNAME"
            uptime
            sleep $DELAY
        fi
        if [[ $REPLY == 2 ]]; then
            df -h
            sleep $DELAY
        fi
        if [[ $REPLY == 3 ]]; then
            if [[ $(id -u) -eq 0 ]]; then
                echo "Home Space Utilization (All Users)"
                du -sh /home/*
            else
                echo "Home Space Utilization ($USER)"
                du -sh $HOME
            fi
            sleep $DELAY
        fi
    exit
        echo "Invalid entry." >&2
        sleep $DELAY
    fi
done
echo "Program terminated."

Breaking Out Of A Loop

bash提供了两个内置的命令, 可以用来控制程序内部循环流动.break命令立即终止一个循环, 循环的下一个语句恢复和程序控制.继续命令循环的原因, 其余的要跳过, 和程序的控制循环的下一次迭代恢复.在这里, 我们看到了一个版本将双双突破并继续程序的, 而菜单:

#!/bin/bash

# while-menu2: a menu driven system information program

DELAY=3 # Number of seconds to display results

while true; do
    clear
    echo "
    Please Select:

    1. Display System Information
    2. Display Disk Space
    3. Display Home Space Utilization
    0. Quit
    "
    read -p "Enter selection [0-3] > "

    if [[ $REPLY =~ ^[0-3]$ ]]; then
        if [[ $REPLY == 0 ]]; then
            echo "Program terminated."
            sleep $DELAY
            continue
        fi
        if [[ $REPLY == 1 ]]; then
            echo "Hostname: $HOSTNAME"
            uptime
            sleep $DELAY
            continue
        fi
        if [[ $REPLY == 2 ]]; then
            df -h
            sleep $DELAY
            continue
        fi
        if [[ $REPLY == 3 ]]; then
            if [[ $(id -u) -eq 0 ]]; then
                echo "Home Space Utilization (All Users)"
                du -sh /home/*
            else
                echo "Home Space Utilization ($USER)"
                du -sh $HOME
            fi
            sleep $DELAY
            continue
        fi
        if [[ $REPLY == 0 ]]; then
            break
        fi
    exit
        echo "Invalid entry." >&2
        sleep $DELAY
    fi
done
echo "Program terminated."
在这个版本的脚本, 我们通过使用真正的命令提供一个退出状态, 而成立一个无限循环(一个从来没有对自己的终止). 由于真正将始终为零的退出状态退出, 循环将永远不会结束. 这是一个非常普遍的脚本技术. 自循环将永远不会结束自己的, 它的程序员提供一些方法来打破循环的时间是正确的的. 在这个脚本中, break命令用于退出循环, 当“0”的选择是选择. 已被列入“继续”命令, 在其他脚本选择, 以便更有效地执行. 继续使用, 脚本将跳过代码, 不需要时选择确定. 例如, 如果“1”的选择是选择和确定, 有没有理由来测试其他的选择.

until

跟while类似, 看例子

#!/bin/bash

# until-count: display a series of numbers

count=1

until [ $count -gt 5 ]; do
    echo $count
    count=$((count + 1))
done
echo "Finished."
执行结果
ecos@ubuntu:~$ ./unitl.sh
1
2
3
4
5
Finished.
ecos@ubuntu:~$

Reading Files With Loops

在下面的例子中, 我们将显示在前面的章节中使用的distros.txt文件的内容:

#!/bin/bash

# while-read: read lines from a file

while read distro version release; do
    printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
        $distro \
        $version \
        $release
done < distros.txt
要重定向循环的文件, 我们重定向操作符后所做的声明.将使用循环读取输入重定向的文件的字段. 读命令后, 将退出读取每一行是一个零退出状态, 直至到达文件结束. 在这一点上, 它会与一个非零的退出状态退出, 从而终止循环. 也有可能进入一个循环管道标准输入:
#!/bin/bash

# while-read2: read lines from a file

sort -k 1,1 -k 2n distros.txt | while read distro version release; do

    printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
        $distro \
        $version \
        $release
done
在这里, 我们采取的sort命令的输出和显示的文本流. 然而, 重要的是要记住, 由于管道将在一个子shell中执行的循环, 在循环中创建或分配的任何变量将丢失, 循环终止时.

第三十一章

Troubleshooting
故障排除

Syntactic Errors

一个错误的一般类是语法. 语法错误涉及键入错误shell语法的一些元素. 在大多数情况下, 这些类型的错误将导致拒绝执行该脚本的外壳.在下面的讨论中, 我们将使用这个脚本来演示常见的错误类型:

#!/bin/bash

# trouble: script to demonstrate common errors

number=1

if [ $number = 1 ]; then
    echo "Number is equal to 1."
else
    echo "Number is not equal to 1."
fi
运行脚本:
ecos@ubuntu:~$ trouble.sh
Number is equal to 1.

Missing Quotes

如果我们编辑我们的脚本, 从第一个echo命令语句中移除尾随引号后:

#!/bin/bash

# trouble: script to demonstrate common errors

number=1

if [ $number = 1 ]; then
    echo "Number is equal to 1.
else
    echo "Number is not equal to 1."
fi
结果是这样的
ecos@ubuntu:~$ trouble.sh
./trouble.sh: line 10: unexpected EOF while looking for matching `"'
./trouble.sh: line 12: syntax error: unexpected end of file
它生成了两个错误. 有趣的是, 行号不是失踪引号被删除, 而是多后面的程序. 为什么我们可以看到, 如果我们按照程序后失踪引号.bash将收盘引号继续寻找, 直到找到一个, 它的第二个echo命令后. bash中变得非常混乱后, 如果命令被打破, 因为现在 fi 语句内引用(但开放)字符串的语法.

在很长的脚本, 这种错误很难找到. 在编辑器中使用语法高亮会有所帮助. 如 vim emacs .

Missing Or Unexpected Tokens

另一个常见的错误是忘记完成一个复合命令, 如if或while. 让我们看看会发生什么, 如果我们在测试中删除 if 后面的分号

#!/bin/bash

# trouble: script to demonstrate common errors

number=1

if [ $number = 1 ] then
    echo "Number is equal to 1."
else
    echo "Number is not equal to 1."
fi
结果是这样的
ecos@ubuntu:~$ trouble.sh
./trouble.sh: line 9: syntax error near unexpected token `else'
./trouble.sh: line 9: `else'

Unanticipated Expansions
意料之外的扩展
#!/bin/bash

# trouble: script to demonstrate common errors

number=

if [ $number = 1 ]; then
    echo "Number is equal to 1."
else
    echo "Number is not equal to 1."
fi

输入结果

ecos@ubuntu:~$ trouble.sh
./trouble.sh: line 7: [: =: unary operator expected
Number is not equal to 1.
我们得到这个颇为神秘的错误消息, 第二echo命令的输出. 问题是在测试命令的数量变量扩张. 当命令:
[ $number = 1 ]
结果试着样
[ = 1]
这是无效的并产生错误. 运算符 = 是二元运算符(它需要在每边的价值), 但首先看重的是缺少这样的 test 命令期望而不是一元运算符(如 -Z).此外, 由于测试失败(因为错误的), if 命令接收一个非零退出代码, 并采取相应的行动, 和行第二个echo命令.

纠正这个问题可以在test命令的周围第一个参数引用:

[ "$number" = 1 ]
变化之后得到结果
[ "" = 1 ]
产生正确数量的参数. 除了为空字符串, 应该用引号的情况下, 可以扩展到多字的字符串值包含嵌入的空格的文件名.

Logical Errors

不同的语法错误, 逻辑错误不会阻止运行一个脚本. 该脚本将运行, 但它不会产生理想的结果, 由于其逻辑的问题. 有无数可能的逻辑错误, 但这里有几个在脚本中发现的最常见的几种:1. 不正确的条件表达式.2. "Off by one"的错误.3. 意料之外的情况.

Defensive Programming
防御性编程
Verifying Input
输入验证

Testing

测试
if [[ -d $dir_name ]]; then
    if cd $dir_name; then
        echo rm * # TESTING
    else
        echo "cannot cd to '$dir_name'" >&2
        exit 1
    fi
else
    echo "no such directory: '$dir_name'" >&2
    exit 1
fi
exit # TESTING
Test Cases

要执行有用的测试, 很重要的开发和应用良好的测试案例.这是通过精心选择的输入数据或操作状态, 反映边和角案件. 在我们的代码片段(这是很简单), 我们想知道的三个特定条件下执行的代码是如何:

1. dir_name 包含现有目录的名称
2. dir_name 包含一个不存在的目录名称
3. dir_name 是空的

Debugging

调试
Finding The Problem Area
Tracing
Examining Values During Execution

第三十二章

流量控制:分支与案例

case

语法

case word in
    [pattern [| pattern]...) commands ;;]...
esac
例子
#!/bin/bash

# read-menu: a menu driven system information program

clear
echo "
Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"
read -p "Enter selection [0-3] > "

if [[ $REPLY =~ ^[0-3]$ ]]; then
    if [[ $REPLY == 0 ]]; then
        echo "Program terminated."
        exit
    fi
    if [[ $REPLY == 1 ]]; then
        echo "Hostname: $HOSTNAME"
        uptime
        exit
    fi
    if [[ $REPLY == 2 ]]; then
        df -h
        exit
    fi
    if [[ $REPLY == 3 ]]; then
        if [[ $(id -u) -eq 0 ]]; then
            echo "Home Space Utilization (All Users)"
            du -sh /home/*
        else
            echo "Home Space Utilization ($USER)"
            du -sh $HOME
        fi
        exit
    fi
else
    echo "Invalid entry." >&2
    exit 1
fi
用 case 之后
#!/bin/bash

# case-menu: a menu driven system information program

clear
echo "
Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"
read -p "Enter selection [0-3] > "

case $REPLY in
    0) echo "Program terminated."
    exit
    ;;
    1)  echo "Hostname: $HOSTNAME"
        uptime
        ;;
    2)  df -h
        ;;
    3)  if [[ $(id -u) -eq 0 ]]; then
            echo "Home Space Utilization (All Users)"
            du -sh /home/*
        else
            echo "Home Space Utilization ($USER)"
            du -sh $HOME
        fi
        ;;
    *)  echo "Invalid entry" >&2
        exit 1
        ;;
esac

Patterns

case Pattern Examples

Pattern Description
a) Matches if word equals “a”.
[[:alpha:]]) Matches if word is a single alphabetic character.
???) Matches if word is exactly three characters long.
*.txt) Matches if word ends with the characters “.txt”.
*) Matches any value of word. It is good practice to include this as the last pattern in a case command, to catch any values of word that did not match a previous pattern; that is, to catch any possible invalid values.

这里是工作模式的例子

#!/bin/bash

read -p "enter word > "

case $REPLY in
    [[:alpha:]])    echo "is a single alphabetic character." ;;
    [ABC][0-9])     echo "is A, B, or C followed by a digit." ;;
    ???)            echo "is three characters long." ;;
    *.txt)          echo "is a word ending in '.txt'" ;;
    *)              echo "is something else." ;;
esac
它也可以结合多种模式, 使用竖线字符作为分隔. 这将创建一个“or”有条件的格局. 大写和小写字符处理这样的事情, 这是有用的. 例如:
#!/bin/bash

# case-menu: a menu driven system information program

clear
echo "
Please Select:

A. Display System Information
B. Display Disk Space
C. Display Home Space Utilization
Q. Quit
"
read -p "Enter selection [A, B, C or Q] > "

case $REPLY in
    q|Q) echo "Program terminated."
         exit
         ;;
    a|A) echo "Hostname: $HOSTNAME"
         uptime
         ;;
    b|B) df -h
         ;;
    c|C) if [[ $(id -u) -eq 0 ]]; then
             echo "Home Space Utilization (All Users)"
             du -sh /home/*
         else
             echo "Home Space Utilization ($USER)"
             du -sh $HOME
         fi
         ;;
      *) echo "Invalid entry" >&2
         exit 1
         ;;
esac
在这里, 我们修改的情况下, 菜单程序菜单选择的数字, 而不是使用字母. 请注意如何在新的模式允许输入大写和小写字母.

第三十三章

Positional Parameters
位置参数

已经从我们的计划中缺少的一个特点是能够接受和处理命令行选项和参数. 在这一章中, 我们将检查shell的功能, 以使我们根据需要获得命令行的内容.

Accessing The Command Line

shell提供了一套称为位置参数包含在命令行中的个别单词的变量. 变量被命名为0到9. 他们可以证明这种方式:

#!/bin/bash

# posit-param: script to view command line parameters

echo "
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
"

一个非常简单的脚本, 当执行不带任何命令行参数显示的值的变量$0 - $9:

Determining The Number of Arguments
shift – Getting Access To Many Arguments
Simple Applications
Using Positional Parameters With Shell Functions

Handling Positional Parameters En Masse

A More Complete Application

第三十四章

Flow Control: Looping With for

在这个流控制的最后一章, 我们将着眼于shell的另一个循环结构. for循环它提供了在一个循环处理序列的一种手段. 这将是非常有用的编程时. 因此, 在bash脚本for循环是一个非常流行的构造,

for: Traditional Shell Form

The original for command’s syntax is:

for variable [in words]; do
    commands
done
我们看看它如何工作的:
ecos@ubuntu:~$ for i in A B C D; do echo $i; done
A
B
C
D
为真正强大的功能, 是一些有趣的方式, 我们可以创建单词列表. 例如, 通过括号扩展:
ecos@ubuntu:~$ for i in {A..D}; do echo $i; done
A
B
C
D
或者路径扩展:
ecos@ubuntu:~$ for i in distros*.txt; do echo $i; done
distros-by-date.txt
distros-dates.txt
distros-key-names.txt
distros-key-vernums.txt
distros-names.txt
distros.txt
distros-vernums.txt
distros-versions.txt
在或者命令替换
#!/bin/bash

# longest-word : find longest string in a file

while [[ -n $1 ]]; do
    if [[ -r $1 ]]; then
        max_word=
        max_len=0
        for i in $(strings $1); do
            len=$(echo $i | wc -c)
            if (( len > max_len )); then
            max_len=$len
            max_word=$i
        fi
    done
    echo "$1: '$max_word' ($max_len characters)"
    fi
    shift
done
#!/bin/bash

# longest-word2 : find longest string in a file

for i; do
    if [[ -r $i ]]; then
        max_word=
        max_len=0
        for j in $(strings $i); do
            len=$(echo $j | wc -c)
            if (( len > max_len )); then
            max_len=$len
            max_word=$j
        fi
        done
        echo "$i: '$max_word' ($max_len characters)"
    fi
done

for: C Language Form

bash的最新版本增加了一个命令语法的第二种形式, 类似于C编程语言中的形式. 许多其他语言, 以及支持这种形式:

for (( expression1; expression2; expression3 )); do
    commands
done
这种形式等同与下面的结构
(( expression1 ))
while (( expression2 )); do
    commands
    (( expression3 ))
done
下面是一个典型的应用:
#!/bin/bash

# simple_counter : demo of C style for command

for (( i=0; i<5; i=i+1 )); do
    echo $i
done
执行它
ecos@ubuntu:~$ ./simple_counter.sh
0
1
2
3
4

第三十五章

內容目录

上一个主题

集群搭建

下一个主题

lnmp

快速搜索

输入相关的模块,术语,类或者函数名称进行搜索