Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103695413
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: LINUX

2008-04-27 15:34:26

    来源:赛迪网技术社区    作者:lynn

单元七实验

bash shell

估计用时:45分钟

目标:掌握定制bash shell的技术,包括创建定制的aliase。

实验前准备:一台装有Red Hat Linux 的机器

实验1:使用aliase

任务:

1、你决定创建一个aliase,使得当你键入cls时,系统会运行clear 命令清除屏幕。由tty1 登录student 开始,然后输入并测试你得aliase。

$ alias cls='clear'

$ alias

$ cls

2、该aliase当你注销后再行登录时变得无效。为了保证每次student 登录时都可用,执行以

下步骤:

$ cd

$ pico .bashrc

找到包含#User specific aliases and functions 这一行,在这行下加上你的aliase:

alias cls='clear'

保存文件后退出。

3、注销后测试你的改动,重新在tty1 登录,并键入:

$ alias

$ cls

4、现在参考ls 的man page,建立一个叫lr 的aliase,调用ls 的5个开关。测试并加入aliase 进你的.bashrc 文件。该aliase 应具备:

a、长格式列出

b、列出以'.'开头的文件

c、"classify" files by appending each entry

d、隐藏文件名内的控制字符

e、按修改时间排序

结果:

得到一个含有新aliase 用于清屏,和一个以时间排序ls的aliase。

实验2:改变bash 提示符

假设:

你决定定制你的bash 提示符以显示当前目录的完整路径和shell的历史数目,并作点相应的美化。

任务:

1、在一个终端窗口,显示当前提示符字串的值。注意提示符内的静态ASCII 字符和反斜杠(忽略符)。

$ echo $PS1

2、改变你的提示符为只显示一串静态的字串:

$ PS1='Red Hat Linux -> '

3、那不是很有用,所以恢复成原来传统的提示符-美元符,接着主机名:

$ PS1='\h $'

4、在主机名和$之间插入bash 历史提示符\!。确认在每个中间都有一个空格。

5、现在参考bash 的man page,查询代表当前目录的特殊字符。(查找PROMPTING,并注意:

你要找的是表示完整路径的特殊字符,而非像默认提示符那样的最后一个目录名)将该特殊字

符插入你的PS1 提示符字串,并前缀一个冒号。

6、你定制的提示符应该像下面这个例子一样。如果不是,继续做。

station1:/home/student 21 $

7、在你的.bashrc 中编辑你的PS1 定义,然后打开一个新的终端窗口以确认你的新提示符正常工作。

实验3:配置shell 选项

假设:

你将使用set 和shopt 来定制你的bash shell 环境。

任务:

1、在tty1 以student 登录。查看当前配置过的shell 选项:

$ set -o

2、注意当前的ignoreeof 选项为关(off)。按 来确认这个操作,看你是否注销了。

3、以student 重登录到tty1 并执行下面的语句,然后测试 ignoreeof 选项:

$ set -o ignoreeof

$

$ Use "logout" to leave the shell

$ set +o ignoreeof

$ se

4、现在使用shopt 命令查看其他的shell 选项:

$ shopt

5、设置并测试 cdspell 选项(注意,看清楚以下命令中故意的拼写错误):

$ cd

$ mkdir test_directory

$ cd test_driectoy

bash: cd: test_driectoy: No such file or directory

$ shopt -s cdspell

$ cd test_driectoy

test_directory

$ pwd

/home/student/test_directory

$ cd ..

$ shopt -u cdspell

$ cd test_driectoy

bash: cd: test_driectoy: No such file or directory

6、你现在看到当你试着从一个shell 提示符执行命令,你可能是在运行:一个外部可执行文件、一个内建的shell 命令、一个aliase或者一个shell 函数等等。有时候检查你输入的命令

究竟是执行了什么是很重要的。使用内建的type 命令询问shell 究竟是执行了什么类型的命令:

$ type cat

cat is hashed (/bin/cat)

$ type cls

cls is aliased to 'clear'

$ type shopt

shopt is a shell builtin

$ type while

while is a shell keyword

结果:

对一些shell 选项有了进一步的了解。

实验4:命令替换

1、检测当在shell 提示符下键入sawfish 的命令的全路径。使用shell 的快捷方式重新执行那条命令,加上-ui 使得运行sawfish-ui,然后使用另一种快捷方式使运行sawfish-themer。

$ which sawfish

$ which .-ui

$ ^ui^themer

2、以sho 为开头,重复最后一个命令。

$ sho

3、当一个命令包括了另一条以backquote(``)包围起来的命令,bash 先执行包围起来的命令,然后在整个命令执行之前将结果替换在``里面。

使用这种技术执行ls -l 列出一个特定目录,该目录是当nautilus 在shell 提示符下输入时程序所在的路径。记住which nautilus 是先被执行的,然后它的结果替换在命令行上,然后

ls -l 在结果上执行。

$ ls -l `which nautilus`

挑战实验:使用shell 函数

任务:

1、在bash shell 提示符下,打入下列行以建立一个简单的shell 函数:

$ lsbytesum()

>{

> TotalByes=0;

> for Bytes in $(ls -l | grep "^-" | cut -c34-42);

> do

> let TotalBytes=$TotalBytes+$Bytes;

> done;

> TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc);

> echo -n "$TotalMeg"

>}

2、检验你新建的函数是否有效:

$ set

...output omitted -- your new function near the bottom...

$ lsbytesum()

{

TotalByes=0;

for Bytes in $(ls -l | grep "^-" | cut -c34-42);

do

let TotalBytes=$TotalBytes+$Bytes;

done;

TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc);

echo -n "$TotalMeg"

}

... complete prompt shown to demonstrate change to prompt ...

[student@station1 student]$ PS1="[\u@\h:\w (\$(lsbytesum) MB)]\$ "

[student@station1:~ (11.971 MB)]$ cd /bin

[student@station1:~ (.476 MB)]$ cd /sbin

[student@station1:~ (.587 MB)]$ cd /etc

[student@station1:~ (.124 MB)]$

3、挑战性问题:

1、要将该函数在每次登录时载入,你需要哪些步骤?

2、要将该函数转换为一个简单的shell script,需要哪些步骤?

结果:

得到一个新的显示当前目录中所有文件总数的shell 提示符。

单元八实验

标准输入输出和管道

估计用时:30分钟

目标:熟悉Red Hat Linux 系统上的标准输入输出和管道实现。

实验前准备:一台装有Red Hat Linux 系统的机器。

实验1:标准输入和输出

任务:

1、打开你平常使用的文本编辑器并建立两个文件:

packages1.txt 应该含有下列8行:

apache

galeon

mozilla

postgresql

procinfo

rpmfind

sawfish

squid

packages2.txt 应该含有下列6行:

anaconda

openssh

gnome-core

samba

sendmail

xscreensaver

2、cat 是Linux 最简单的文本过滤器(filter)。它的工作就是将它的输入——作为它的一个参数的文件名,或者是从标准输入中输入,并且输出不变地输出它到标准输出。

用packages1.txt 来测试cat:

$ cat packages1.txt

3、如果cat 后没有跟参数,它就期待从标准输入的输入。这意味着如果你键入cat 后按回车,似乎什么事也没发生。实际上,cat 在耐心的观察标准输入,等待输入的到达。如果你打入一些字符并按回车键,cat 将你输入的送到标准输出——即原封不动的将你的输入送出。结束

cat 命令,按。这是通用的输入结束信号。

$ cat

Type some sample text, then press return.

4、多数Linux 文本进程命令都以过滤器实现(filter),这意味着它可以从标准输入读出,然后对它做一些事,然后送到标准输出。这些命令和cat 很像,但是它们的输出和输入不同。

本单元介绍过的tr,就是这样一个filter。如果你给tr 两个字串作为参数,那么它从标准输入中读出,然后从第一个字串的字母到第二个字串中的字符进行翻译,然后将翻译后的字串写到标准输出中。

重复前一个例子,改用tr。给出的参数将元音字母从小写改为大写。

$ tr 'aeiou' 'AEIOU'

Type some sample text, then press return.

5、要告诉shell 程序的输出不要送到标准输出,而是要重定向到一个文件,那么使用重定向符 >

重复第一个cat 的例子,重定向标准输出到packages1.catfile。这将创建一个packages1.txt的拷贝。cat 这个输出文件,并且用diff 和ls 检验它是否和原先的文件拥有相同的内容。

$ cat packages1.txt > packages1.catfile

$ cat packages1.catfile

$ diff packages1.txt packages1.catfile

$ ls -l packages1*

6、在一个已存在的文件中追加内容,使用>> 操作符。

在packages1.catfile 后追加packages2.txt 的内容,并且检验结果

$ cat packages2.txt >> packages1.catfile

$ cat packages1.catfile

7、如果没有文件名作为参数给cat,并且标准输出(原书写standard input,我觉得错了)定向为一个文件,那么屏幕上打的任何字符直到按下,将会被重定向到那个文件。这种方法可以很容易建立一个新文件。

$ cat > typedin.txt

This time , when text is typed at the keyboard,

It is not echoed back to the screen,

It is instead redirected to the file typedin.txt

$ ls -l typedin.txt

$ cat typedin.txt

8、重复前面的步骤,替换cat 为tr 命令。

$ tr 'aeiou' 'AEIOU' > trfile.txt

This time , when text is typed at the keyboard,

It is not echoed back to the screen with the translation made,

It is instead redirected to the file trfile.txt

$ ls -l trfile.txt

$ cat trfile.txt

9、使用set -o 显示当前bash 的noclobber 选项。检验当重定向输出到一个文件时你的确可以“修补(clobber)”该文件。

$ set -o

$ ls -l /tmp > trfile.txt

$ ls -l trfile.txt

$ cat trfile.txt

10、使用set 修改noclobber 选项,然后检验操作:

$ set -o noclobber

$ echo "new contents" > trfile.txt

bash: foo: cannot overwrite existing file

11、cat 可以接受一个文件名,或者一个重定向的文件作为标准输入。测试下面两个命令:

$ cat packages1.txt

$ cat < packages1.txt

12、然而,tr 不允许文件名作为参数,它需要从标准输入的输入。

$ tr 'aeiou' 'AEIOU' < packages1.txt

13、标准输出和输入可以同时被重定向,就像下面这个例子。和上面一样,从packages1.txt

定向输入到tr,但是这次需要重定向输出。屏幕上没有输出——它输出到了文件

packages1.trfile.txt。

$ tr 'aeiou' 'AEIOU' < packages1.txt >pacakges1.trfile.txt

$ ls -l packages1.txt packges1.trfile.txt

$ cat packages1.trfile.txt

实验2:管道

1、为了将标准输出从一个命令定向到另外一个命令作为标准输入,引入了一种叫做管道的特殊的重定向机制。

若没有管道,打印一个目录列表,至少需要两步——而且还有一个文件作为打印后没用的副产品。需要第三步来删除它。(注意,这些步骤当你没有打印机时仅作演示使用)

$ ls -l > /tmp/ls.txt

$ lpr /tmp/ls.txt

$ rm /tmp/ls.txt

如果使用管道,这三步可以在一个短命令中完成——并且不需要建立临时文件、再删除。注意lpr 从标准输入中得到输入,所以没有必要加任何参数。

$ ls -l | lpr

2、管道经常用于一个可能生成多行的命令,输出到less。命令执行的顺序是从左开始。当输出生成后,通过管道传到在右边等待的命令。less 从一个管道中等待输入,所以不需要加任何参数。(用空格键翻页,然后按q退出)

$ ls -l /usr/bin | less

实验3:练习

如果你需要答案,答案在后面列出。但请用本单元提供的信息和man page努力完成这些练习。

1、为命令cal 在你的home 目录下建立一个格式化的man page 拷贝,文件名为cal.man

2、用哪个单条命令可以配置你的输入是键盘输入、输出是打印机输出?

3、你如何将/usr/bin 下的名字以'c'或者'd'开头的文件长列表输出到打印机?

实验3答案

2、lpr

lpr 若给出文件名作为参数,则它打印文件内容。如果没有文件名给出,则它从标准输入读入数据。当你按后你从键盘输入的数据将被打印出来。

3、ls -l /usr/bin/[cd]* | lpr

单元九实验

字符处理

估计用时:60分钟

目标:熟悉几种Red Hat Linux 上的字符处理程序。

实验前准备:一台装有Red Hat Linux 的机器,并在你的home 目录中有/etc/passwd 的拷贝。

实验1a:基本字符处理

任务:

1、拷贝/etc/passwd 到你的home 目录

$ cd

$ cp /etc/passwd .

2、每个帐号都会在/etc/passwd 中占有一行。使用wc 统计passwd 文件的行数。

$ wc -l passwd

你系统上的帐号数有_______个。

3、生成一个用户shell 列表并将它存在另一个文件中:

$ cut -d: -f7 passwd > shells

4、使用cat 查看你的shells 文件。你将感到虽然文件存储了信息但是组织得不理想。将这些行排序并输出到一个新文件:

$ sort shells > sorted.shells

5、你的文件包含了多个重复的值。使用uniq 来统计每个值出现多少次:

$ uniq -c sorted.shells > uniq.sorted.shells

为什么在传给uniq 之前必须先要将输出排序?

(提示:试试uniq -c shells 和 man uniq)

6、要生成一个数字逆序排列的,你机器上使用的shell(当然你机器上使用的shell 数可能和这里列出的不同):

$ sort -nr uniq.sorted.shells

18 /sbin/nologin

5 /bin/false

4 /bin/bash

2 /dev/null

1 /sbin/shutdown

1 /sbin/halt

1 /bin/sync

1

结果:

得到一个数字逆序排列的、和系统中帐号相关的shell 列表。

实验1b:练习

设计,然后写下每个练习的解。记住,答案是你执行的命令,而不是输出。每个解应该只有一句命令,并且至少由一个管道实现。你可能需要翻阅man page。答案在实验最后给出。

1、/usr/bin 目录下有多少文件?输出应该是单个的整数。提示:设计一个命令可以每行列出一个文件,然后想想如何统计这些行数。

2、对/usr/share/doc/nautilus-1.06/NEWS 作一次拼写检查。

3、练习2 得到多少不重复的(unique)的单词?

4、练习2 中,输出重复出现超过一次的单词列表。

实验2:用grep 作字符处理

任务:

1、使用grep 显示你home 目录下的passwd 文件(/etc/passwd的拷贝)中,以'g'开头的帐户:

$ grep ^g passwd

2、显示所有的使用bash shell的帐户:

$ grep bash$ passwd

3、显示所有不使用bash shell 的帐户

$ grep -v bash$ passwd

4、为了演示diff 的使用,建立一个修改过的passwd 拷贝。使用grep 删除任何含有'N'或者

'P'的行:

$ grep -v [NP] passwd > modified.passwd

5、最后,用tr 转换所有的大写字母为小写字母:

$ tr "A-Z" "a-z" < modified.passwd > modified2.passwd

6、使用cat 查看你原先的passwd 和modified2.passwd。如果不仔细看的话,区别难以找到。

使用diff 生成两个文件之间差异的列表,用统一格式:

$ diff -U 0 modified2.passwd passwd

实验3:正则表达式和字符操作

设计,然后写下每个练习的解。记住,答案是你执行的命令,而不是输出。你可能需要翻阅

man page。答案在实验最后给出。

任务:

1、试着用grep 将/usr/share/dict/words 中和查找项相符的项输出。例如,显示所有包含

fish 的项:

$ grep fish /usr/share/dict/words

仔细比较上面和下面的输出,并找出grep 的-i 开关的用处:

$ grep -i fish /usr/share/dict/words

2、使用grep 的man page,构造一个命令可以每行含有在words 文件中找到的fish 项的输出,且每行前后都空两行(提供其他的内容),然后执行它。

3、使用grep 的man page,构造一个命令可以输出fish 项在words 文件中找到的个数,然后执行它。

4、使用grep 的man page,构造一个命令可以将fish 项在words 中匹配的行,包括它的行号

。在哪行找到了starfish?

5、列出/usr/share/dict/words 文件中含有t、一个元音字母、接着是sh的单词。

6、为/usr/share/dict/words 构造一个匹配abominable, abominate, anomie 和 atomize(

但不匹配其他)的正则表达式。

7、在/usr/share/dict/words 中有多少词包括t,一个元音字母,以sh 结尾的单词?构造命令并执行,它应只输出个数。

8、列出/usr/share/dict/words 中只含16个字母的单词。

9、/usr/share/doc 是个有用的信息源。我们在后面几个任务中将使用这个目录中的文件。

列出含有词'expansion'的普通文件的文件名

10、显示'Linux'这个词在/usr/share/doc/bash-2.05a目录下的文件中的出现频率。但是不要

输出含0次的文件。提示:先统计所有文件的个数,然后考虑你如何禁止与某一项相匹配的行的输出。

11、列出在/usr/share/doc 下所有含有'Havoc' 的文件的文件名

12、你可以使grep 递归查找目录下的文件:

grep -R --include=

使用这种技术,将/usr/share/doc 下所有含有'ethernet' 的文件列出。

13、只显示那些文件的文件名

14、特殊的挑战性任务:

设计一个命令,可以显示在练习13显示的文件中含有'authentication'的文件。记住

backquotes(``)可以先计算内表达式,然后将其替换命令行中的相应内容。

15、使用类似的技术查找/usr/share/doc 下含有'regular expression',但不含'perl'的文件(均为大小写敏感)

16、列出/usr/share/doc 下所有含有美国州名和9位邮政编码的(格式:XX NNNNN-NNNN)、

且文件名以".txt"结尾的文件。

实验4:探索管道的应用

任务:

1、在实验1a中,你使用了多种字符处理程序,在4步骤内建立了排序的shell 列表。在本实验中你将完成同样的任务,但是只用一步。

为了建立排序的shell 列表,组合实验1a中步骤3到6的命令。和上次实验不同,这次不需要任何临时文件。因为整个操作多次将输出管道定向到另一个命令中。

$ cut -d: -f7 passwd | sort | uniq -c | sort -nr

18 /sbin/nologin

5 /bin/false

4 /bin/bash

2 /dev/null

1 /sbin/shutdown

1 /sbin/halt

1 /bin/sync

1

2、要查看所有以root 运行,按字母表排序的进程列表,使用ps 输出带用户名的进程列表,然后管道定向到grep 以产生只有root 所拥有的进程列表。^告诉grep 只在每行的行首查找root 字串

$ ps auxw | grep ^root

3、假设你需要将这些数据传给一个只需要进程名的script。为了产生该列表,使用tr 和cut的组合。首先,用tr 将空格压缩成cut 能理解的分界符(这里是a%)。然后,使用cut 只显示进程名(tr 输出的第11列)

$ ps auxw | grep ^root | tr -s [:blank:] [a%] | cut -d% -f11

4、现在我们有了属于root 进程的列表。但是我们让cut 只显示第11列,这样我们失去了该进程的命令行参数。在第二步中,我们知道最后一个进程syslogd带有参数-m 0,但是在第三步

我们只看到syslogd。将-f11 改为-f11-,使得cut 将11列到最后的列全部裁减输出。

$ ps auxw | grep ^root | tr -s [:blank:] [a%] | cut -d% -f11-

5、我们几乎已经达到了需要的输出。记住我们使用了tr 转换空格为分界符a%,以使cut 可用。现在我们需要再次用tr 将%back 转换成空格。

$ ps auxw | grep ^root | tr -s [:blank:] [a%] | cut -d% -f11- | tr [%back] "[]"

6、就像你前面看到的,在使用命令行工具时,管道是一种非常有用的工具。前面这些步骤完成了我们的工作,但是在花费很多时间折腾输出前,请务必确认该程序是否有可能格式化成你所需要的格式。ps,特别地,能输出几乎你能想象的格式。请注意看下面命令的开关是如何完成我们需要的输出的:(哎!)

$ ps -u root -o args

结果:

使用管道的命令的组合,输出root 拥有的系统进程列表。

实验3答案:

1、grep -B2 -A2 "fish" /usr/share/dict/words

4、grep -c "fish" /usr/share/dict/words

5、 grep "t[aeiou]sh" /usr/share/dict/words

6、 "^a.om.*e$"

7、 grep -c "t[aeiou]sh$" /usr/share/dict/words

8、 grep -c "................" /usr/share/dict/words

(为什么不是 grep -c ".\{16\}" /usr/share/dict/words ?)

9、 grep -l expansion /usr/share/doc/bash-2.05a/*

10、 grep -c "Linux" /usr/share/doc/bash-2.05a/* | grep -v ":0"

11、grep -R "Havoc" /usr/share/doc

12、 grep -R --include="*txt" ethernet /usr/share/doc

13、 grep -lR --include="*txt" ethernet /usr/share/doc

14、 grep -i autentication `grep -lR --include="*txt" ethernet /usr/share/doc`

15、 grep -ivl perl `grep -Rli --include="*txt" "regular expression"

/usr/share/doc`

16、 grep -R --include="*.txt" " *[A-Z][A-Z] *[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]"

阅读(218) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~