分类: 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]" |