时间列表
简介
首先进入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 是停止任务并放入后台
用户可以使用 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 # 退出终端
尝试一些简单得命令
date cal df free
显示当前的时间和日期
ecos@ubuntu:~$ date Fri Jun 10 10:44:29 CST 2011
显示当前月的日历
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
查看磁盘驱动的类型使用情况
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
显示内存类型使用情况
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 - 打印目录的内容
ecos@ubuntu:~$ pwd /data/svn/ecosdoc/source/misc
改变目录, 绝对路径 / , / 代表根目录
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 命令
ecos@ubuntu:~$ ls Desktop Documents Music Pictures Public Templates Videos
现在,我们知道了如何移动文件系统, 稍后,我带领大家参观我们的Linux系统. 然而,在我们开始前我们要学习一些指令,沿途会有用的.
ls - 打印目录的内容 file - 打印文件类型 less - 显示文本文件的内容
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, 使用方法如下
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 打印文本文件内容
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 目标目录
在开始使用命令之前,我们需要谈一谈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”结尾的文件 |
可以使用通配符,接受任何命令的文件名作为参数,但我们会谈论更多关于在第八章.
复制文件/目录
例
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 # 递归复制
创建目录
参数
Option | Meaning |
---|---|
-p | 递归创建 |
例
ecos@ubuntu:~$ mkdir dir ecos@ubuntu:~$ mkdir dir1 dir2 dir3 # 创建多个文件夹 ecos@ubuntu:~$ mkdir -p /dir1/dir2/dir3 # 递归创建文件夹
移动文件/文件夹 也用于重命名
常用参数
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
删除(delete)文件/文件夹
参数
Option | Meaning |
---|---|
-r | 删除文件夹, 递归删除 |
-f | 强制删除 |
例子
ecos@ubuntu:~$ rm file1 ecos@ubuntu:~$ rm file1 dir1 ecos@ubuntu:~$ rm -r dir1 ecos@ubuntu:~$ rm -rf dir1
链接
参数
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
获得帮助信息, 在每个shell命令的后面加上--help参数, 如
ecos@ubuntu:~$ ls --help ...
获得命令指南
用法
man program man section search_term例子
ecos@ubuntu:~$ man ls ... ecos@ubuntu:~$ man 5 passwd ...
恰当的显示合适额命令,这是一个搜索为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
显示一个简短的描述
例子
ecos@ubuntu:~$ whatis ls ls (1) - list directory contents ecos@ubuntu:~$ whatis vim vim (1) - Vi IMproved, a programmers text editor
信息页显示为读者程序命名,适当的不够,信息. 信息页是超链的很像的网页.
命令 | 行动 |
---|---|
? | 显示命令的帮助 |
PgUp or Backspace | 显示前一页 |
PgDn or Space | 显示下一页 |
n | next, 显示下一个节点 |
p | previous, 显示前一个节点 |
u | up, 显示当前节点的父节点,通常是一个菜单 |
Enter | 超链接进入遵循游标目前的位置 |
q | 退出 |
例子
ecos@ubuntu:~$ info coreutils ...
创建自己的命令
例子
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 ...
可以链接一个或者多个文件
例子
ecos@ubuntu:~$ cat file1 aaa ecos@ubuntu:~$ cat file2 bbb ecos@ubuntu:~$ cat file1 file2 aaa bbb
管道 命令的能力从标准输入读取数据,发送到标准输出 利用壳功能叫做管道. 使用管道操作”|”(垂直杆) 标准输出一条指令可以标准输入管道连接到另一个:
语法
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 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 zipsplitgrep是使用率非常高的一个命令, 最多的实在做查询条件出现, 作用相当与过滤.(我个人观点)
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
标准输入与输出文件
例子
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”.
历史记录
一些例子
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”, 除非你绝对确定历史内容的列表条目.
除了要掌握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 (---)
语法
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-xA directory with the sticky bit set:
drwxrwxrwt
当前日期: 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)的说明.
在不同的时期,我们会发现有必要接受另一个用户的身份. 经常我们要赢得超级使用者特权进行了一些行政任务, 但它也是可能”变成“另一个一般的使用者对诸如测试一个帐户. 有有三种方式去另一个身份.
切换用户
语法
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 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
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程序有许多选项,但在它最简单的形式是使用这样的:
如
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命令:
ecos@ubuntu:~$ top ...
现在我们可以看到和监控过程,让我们获得一些控制他们. 为我们的实验中,我们将用一个小项目叫做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:~$ # 什么都没有
在这一章中,我们将与下列命令:
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. |
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. |
配色就这样吧
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 [-t vfstype] [-o options] device dir
其中:
cp /dev/cdrom /home/sunky/mydisk.iso 或 dd if=/dev/cdrom of=/home/sunky/mydisk.iso # 执行上面的任何一条命令都可将当前光驱里的光盘制作成光盘镜像文件/home/sunky/mydisk.iso
mkisofs -r -J -V mydisk -o /home/sunky/mydisk.iso /home/sunky/ mydir # 这条命令将/home/sunky/mydir目录下所有的目录和文件制作成光盘镜像文件/home/sunky/mydisk.iso, 光盘卷标为:mydisk
# 建立一个目录用来作挂接点(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客户端(远程登录程序)
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程序(一些系统使用类似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程序是用于检查各种网络设置和统计. 通过使用它的许多选项, 我们可以看看各种功能在我们的网络设置. 使用"-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
另一种流行的命令行程序文件下载是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来递归下载, 下载的文件背景(允许您注销而继续下载), 并完成下载一个部分下载的文件. 这些功能是有据可查的在其好于平均水平的手册页.
远程登录
例子
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 .
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 - 在目录中搜索文件
查找文件的简便方法 该定位程序执行的路径快速数据库检索和输出每名称相匹配一个给定的子串.
例子
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 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 3377find 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命令执行了一个有趣的功能. 它接受来自标准输入的输入, 并将其转换成一个指定的命令的参数列表.
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
有用的东西呀, 看了就知道!
例子
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的程序是用来压缩一个或多个文件. 当执行时, 它取代了原来的压缩版本的原始文件. 相应的用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
类似于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
在软件类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 -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 [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 zipsplitgrep 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
插入符号(^)和美元符号($)字符被视为在正则表达式锚. 这意味着, 正则表达式中(^)表示开头或($)表示结尾:例子
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选项, 以产生逆相匹配, 使我们只输出列表中的行不匹配指定表达式.表达式本身包含两端的锚元字符, 以确保数量两端没有多余的字符. 这个表达式还要求括号中存在一个有效的数字不像我们以前的电话号码.
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
看下面的例子
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:~$
排序文件、对已排序的文件进行合并, 并检查文件以确定它们是否已排序. 使用相同的技术, 我们与 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 的用法
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 选项.
显示每行从开头算起 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 工具可以对文件中的域进行合并. 它从每个源文件中提取一行内容, 并将其与另外一个源文件中的一行内容合并在一起.
举例来说, 假设文件 “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 文件内容的最后
根据公共字段(关键字)来合并两个文件的数据行. 因此最简单的使用方式就是指定两个数据文件名, 这两个文件的第一列就是公共字段, 字段 之间以空白分隔. 内连接(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
看例子不说话
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
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
例子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
例子
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 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 - 文件格式系统
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
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.
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$
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$
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>
上例子
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
在最简单的术语, 一个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 -adand:
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:~$
很像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
总结在这一章中, 我们开始了一个项目, 我们会通过的过程中建立一个成功的剧本. 我们介绍的概念, 变量和常量, 以及他们如何可以用来. 他们是第一个应用, 我们会发现许多参数扩展. 我们也期待在如何产生输出从我们的脚本, 和各种方法嵌入文本块.
自顶向下设计
作为项目获得更大和更复杂的, 他们变得更难设计, 代码和维护. 如同任何大型项目, 它往往是一个好主意打破大型, 复杂的任务分成一系列的小, 简单的任务.让我们想象一下, 我们试图描述一个共同的, 日常的任务, 去市场买菜, 一个人从火星. 我们可以描述整个过程如下一系列步骤:
然而, 一个人从火星可能需要更多的细节. 我们可以进一步分解成子任务“公园”这一系列步骤:
“关闭”任务可以进一步细分为步骤包括“关闭点火开关, “取下点火钥匙”等, 直到每一步的整个过程中会得到了市场的充分定义.这一过程中确定了顶级的步骤和发展越来越详细的意见, 这些步骤叫做自顶向下设计.这项技术使我们能够打破大型复杂的任务, 为许多小的, 简单的任务. 自顶向下的设计是一种常见的方法, 设计程序和一个非常适合编程的特别.
在这一章中, 我们将使用自顶向下设计的进一步发展我们的报告生成的脚本.
为我们的下一个阶段的发展, 我们会添加一些额外的任务之间的步骤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分支
利用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 noThe if statement has the following syntax:
if commands; then commands [elif commands; then commands...] [else commands] fi
退出状态
命令(我们写包括 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:~$
到目前为止, 最常用的命令, if is test . test命令执行各种检查和比较. 它有2个等价形式:
test expressionand the more popular:
[ expression ]
文件表达式
下面的公式来评估文件的状态:
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:~$
字符串表达式
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:~$
整数表达式
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.
一个现代版的测试
新版本的 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.
演示
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
结合表达式
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.重要的是要知道如何使用测试, 因为它是非常广泛的使用, 但[]显然更有价值和更容易编码.
控制运算符:另一种分支
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 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'
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 选项, 密码短语的字符不显示所键入的呼应.
通常情况下, 外壳上执行读取输入单词分割. 正如我们所看到的的, 这意味着, 由一个或多个空格成为单独的项目, 在输入行分隔的多个单词, 并通过读取分配给单独的变量.这种行为是一个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和它的环境被破坏, 丢失和分配的影响.
这里使用的字符串, 是解决此问题的途径之一. 另一种方法是会在后面的章节讨论.
验证输入
随着我们新的能力, 有键盘输入一个额外的编程挑战, 验证输入. 很多时候, 一个精心编写的程序和写得不好之间的差异是在程序的能力, 处理意外.通常情况下, 意外出现在错误的输入形式. 我们已经做了我们在前一章中, 我们检查的整数的值的一个评价方案这一点, 并筛选出空值和非数字字符.重要的是要执行这些类型的编程检查每一个程序接收输入, 防止无效数据的时间. 由多个用户共享的方案, 这一点尤为重要.省略这些保障在经济利益可能会原谅, 如果一个程序是用于执行某些特殊任务的作者的一次, 况且. 即使这样, 如果程序执行危险的任务, 如删除文件, 它会是明智的, 包括数据验证, 以防万一.
这里有一个验证各种输入的例子
#!/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, 以及一个适当的使用正则表达式
菜单
常见的类型是所谓的互动菜单驱动. 在菜单驱动的程序, 用户是一个选择列表, 并要求选择一个. 例如, 我们可以设想, 提出了以下程序:
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这个脚本是逻辑上分为两部分.
在这里它是用来防止脚本执行后的行动已进行了不必要的代码. 但它在这个脚本在程序中存在多个退出点通常是一个坏主意(它使程序逻辑很难理解).
#!/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."
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”的选择是选择和确定, 有没有理由来测试其他的选择.
跟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:~$
在下面的例子中, 我们将显示在前面的章节中使用的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 故障排除
一个错误的一般类是语法. 语法错误涉及键入错误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.
如果我们编辑我们的脚本, 从第一个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 .
另一个常见的错误是忘记完成一个复合命令, 如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'
意料之外的扩展
#!/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 ]产生正确数量的参数. 除了为空字符串, 应该用引号的情况下, 可以扩展到多字的字符串值包含嵌入的空格的文件名.
不同的语法错误, 逻辑错误不会阻止运行一个脚本. 该脚本将运行, 但它不会产生理想的结果, 由于其逻辑的问题. 有无数可能的逻辑错误, 但这里有几个在脚本中发现的最常见的几种:1. 不正确的条件表达式.2. "Off by one"的错误.3. 意料之外的情况.
防御性编程
输入验证
测试
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
要执行有用的测试, 很重要的开发和应用良好的测试案例.这是通过精心选择的输入数据或操作状态, 反映边和角案件. 在我们的代码片段(这是很简单), 我们想知道的三个特定条件下执行的代码是如何:
1. dir_name 包含现有目录的名称 2. dir_name 包含一个不存在的目录名称 3. dir_name 是空的
调试
流量控制:分支与案例
语法
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
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的功能, 以使我们根据需要获得命令行的内容.
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:
Flow Control: Looping With for
在这个流控制的最后一章, 我们将着眼于shell的另一个循环结构. for循环它提供了在一个循环处理序列的一种手段. 这将是非常有用的编程时. 因此, 在bash脚本for循环是一个非常流行的构造,
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
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