资源描述
《计算机软件基础》多媒体教程
第六讲
第一章 操作系统及Unix Shell
1.8 C Shell
本节将介绍C shell的主要特点,并且在“附录B”中提供了B shell、Bash和C shell的比较一览表,供同学们查阅。包括:
※ 基本特点
※ 变量
※ 特殊变量
※ Shell环境的识别
※ 输入输出语句
※ 运算语句
※ 输入变量和程序变量
※ 运算符和表达式
※ 控制结构及相关语句
※ 命令行编辑
※ 假名(别名)机制(C shell)
※ 命令史机制(Bash和C shell)
※ 工作目录栈(Bash和C shell)
※ 函数(Bash)
1.8.1 C shell的特点
※ 运行配置文件
⊙ 配置文件
B shell: $HOME/.profile
C shell: $HOME/.cshrc,$HOME/.login
Bash: $HOME/.bashrc,$HOME/.bash_profile
⊙ 运行配置文件的命令
运行配置文件的作用是获得相应的shell环境的设置。运行各种shell环境配置文件的命令分别为:
B shell和Bash: .□配置文件
C shell: source□配置文件
例如在Bash中,运行配置文件的操作为:
$ .□~/.bashrc $是B Shell和Bash的缺省待命符
在C shell中,运行配置文件的操作为:
% source□~/.cshrc %是C Shell的缺省待命符
% source□~/.login
※ shell程序的识别
运行一个shell程序,必须用某个shell解释器(B shell、Bash或C shell)来解释这个shell程序。在UNIX中,不是通过文件的后缀来确定shell程序的种类,而是由程序文件的首行进行识别。
UNIX B shell的首行: #! /bin/sh 则按B shell来解释程序
UNIX C shell的首行: #! /bin/csh 则按C shell来解释程序
Linux Bash的首行: #! /bin/bash 则按Bash来解释程序
通常,缺省以上首行的程序将默认为B shell,如果首行是注释而不是说明Shell种类的将作为C shell进行解释。
启动某个shell解释器运行一个shell程序,也仅仅表示在该程序运行时用该shell解释器来解释程序中的各种shell语句和控制结构。一旦程序结束,将仍然回到原来的shell环境。
在B shell环境下运行C shell程序,与执行/bin/csh转到C shell环境是不一样的。一旦这个C shell程序结束,将依然处在B shell环境之下而不会改为C shell环境。例如,csh_file是C shell程序:
$ csh_file 在B shell下运行C shell程序
$ B shell环境
$ /bin/csh 在B shell下转到C shell
% C shell环境
例如, 以下三个shell文件将自动选择正确的shell解释器运行:
B shell文件sh0:
#! /bin/sh
if [ ! -d $1 ]
then
echo not dir
fi
C shell文件csh0:
#! /bin/csh
if ( ! -d $1 ) then
echo not dir
endif
Bash文件bash0:
#! /bin/bash
if ! -d $1
then
echo not dir
fi
在以下三个shell文件中,sh_1将按B shell执行,sh_2将按C shell执行,sh_3将按用户登录时的shell执行。由于sh_3使用的命令与shell种类无关,任何一种解释器都能运行:
shell文件sh_1:
if [ ! -d $1 ]
then
echo not dir
fi
shell文件sh_2:
#any comment
if ( ! -d $1 ) then
echo not dir
endif
shell文件sh_3:
pwd
echo $HOME
ls
ls $HOME
※ 目录/文件名的补齐(Filename completion)
C shell也提供目录/文件名的自动补齐功能。与Bash不同的是:
1) 必须先执行命令set filec,以启动文件名补齐功能。
2) 在执行以目录或者文件为参数的echo、ls等命令时,请求文件名补齐的是<ESC>键。
3) 如果按<ESC>键不能完成自动补齐功能,说明可识别的文件名模糊难辨,则可以按^D键,请求列出所有可能匹配的目录/文件名。
【例1-33】目录/文件名补齐示例
% set filec 启动文件名补齐功能
% ls
a.out c shell 假设c和shell是目录
% vi s<ESC> 在vi s后按<ESC>, 将补齐为shell
% vi shell/^D 按斜杠/键及^D键,请求列出shell下的所有文件
a.out proj2 proj.c projtest.c tmp/ shell下有四个文件一个目录
% vi shell/p<ESC> 继续键入p,再按<ESC>
% vi shell/proj 可匹配到proj
% vi shell/projt<ESC> 继续键入t,再按<ESC>
% vi shell/projtest.c<CR> 可匹配到projtest.c,再按回车,将执行命令vi shell/projtest.c
※ 改变stderr的定向
C shell在改变标准输入输出定向时,改变stdin,stdout的用法与B shell相同,但是在改变标准出错输出定向时,形式不同:
⊙ B shell和Bash
2> file
⊙ C shell
>& file 表示将stderr和stdout合并到文件file。
例如,将cc(C编译程序)的出错信息存入文件errfile。
在B shell和Bash中,操作为:
$ cc b.c 2> errfile
在C shell中,操作为:
% cc b.c >& errfile
※ 变量的删除和测试
⊙ B shell和Bash的变量定义语句
变量=值
⊙ C shell的变量定义语句
set 变量=值
⊙ Bash和C shell的变量删除语句
unset 变量
⊙ C shell增加的测试变量定义的特殊变量
无论是普通变量还是环境变量,C shell提供测试某个变量是否已定义的特殊变量:
$?变量
则将获得一个数值。如果为0,表示该变量尚未定义。如果为1,表示该变量已经定义。
【例1-34】C shell变量定义示例
% set x=finish 定义x的值为finish
% echo x=$x ‘?def?=’$?x
x=finish ?def?=1 显示x的值为finish,变量已定义
% unset x 删除变量
% echo x=$x ‘?def?=’$?x
x= ?def?=0 执行结果表示x被删除,未定义
※ 环境变量
B shell和Bash的环境变量通常全部用大写字母表示。
C shell的环境变量通常全部用小写字母表示。同时,在C shell环境下,也能引用B shell(用大写字母表示)的环境变量。
定义环境变量的语句格式为:
setenv□环境变量□值
set□变量=值
使用setenv定义环境变量,可以直接生效,而不需要使用export命令。例如:
% setenv□path□“.:$path”
如果将环境变量的设置在写入配置文件后希望立即生效,必须运行配置文件。
※ 常用环境变量
⊙ username 用户名,即注册时用的账号
只能引用,不能修改。
⊙ ~ 用户的注册目录
在Bash和C Shell中:
“cd ~”等价为”cd”或者”cd $HOME”,
“cd ~/bin”等价为”cd $HOME/bin”或者”cd ; cd bin”。
在C Shell中,~还可以用来匹配其他用户的注册目录。例如,用户me01想查看另外一个用户me00注册目录下的文件,可以执行以下命令:
% ls□~me00
⊙ path 可执行路径
例如:已设置的可执行路径为“/bin:/usr/bin”。如果需要增加两个可执行路径“.”(当前目录)和“~/shell”,则命令为:
% setenv path “.:~/shell:$path”
⊙ prompt 缺省的一级待命符
通常系统管理员将prompt的初值设为%,用户可以修改。例如:
% setenv prompt “[$username@`host`]\!>□”
[wenqing@fdme00]5>□
其中,`host`表示将执行host命令,以获得当前使用的宿主机名,\!表示当前的命令序号(命令序号将在命令史中介绍)。
⊙ term 当前使用的终端类型
⊙ tty 当前使用的终端名
※ 查看环境变量的方法
% echo $环境变量
% setenv $环境变量
% printenv $环境变量
% env
% set
※ 输入输出语句
⊙ B shell和Bash的输入语句
read 变量 从stdin读取变量
⊙ C shell的输入语句
set 变量=$< 从stdin读取变量,$<表示标准输入
⊙ B shell输出语句的禁止换行
echo 变量或字符串 \\c
⊙ Bash输出语句的禁止换行
echo -n 变量或字符串
⊙ C shell输出语句的禁止换行
echo -n 变量或字符串
※ 运算语句
⊙ B shell的运算语句格式:
变量=`expr□表达式□运算符□表达式 `
⊙ Bash的运算语句格式:
let□“变量□=□表达式□运算符□表达式 ”
⊙ C shell的运算语句格式:
@□变量□=□表达式□运算符□表达式
例如,以下运算语句是等价的:
B shell:
p=`expr□$p□+□1`
Bash:
let “p□=□p□+□1”
C shell:
@□p□=□$p□+□1
@□p++
@□p□+=□1
※ 文件测试表达式
⊙ B shell的文件测试表达式
-r file 文件file存在且可读
-w file 文件file存在且可写
-x file 文件file存在且可执行
-s file 文件file存在且非空(C shell不可用)
-d dir dir是一个目录
⊙ C shell增加的文件测试表达式
-f file 文件file存在并且是普通文件(plain file)
-e file 文件file存在(existance)
-o file 文件file存在而且用户是该文件的主人(owner)
1.8.2 C Shell控制结构
※ if结构
if (□表达式□)□then
语句组
else if(□表达式□)□then
语句组
else
语句组
endif
else if和else可以省略。
请比较以下shell程序:
B Shell
Bash
C Shell
if [□$#□-eq□0□]
then
echo no args
else
echo args=$*
fi
if $#□-eq□0
then
echo no args
else
echo args=$*
fi
if (□$#argv□==□0□) then
echo no args
else
echo args=$argv
endif
※ for结构
foreach□索引变量 ( 变量表 )
语句组
end
请比较以下shell程序:
B Shell
Bash
C Shell
for□i□in□$*
do
if [□!□-s□$i□]
then
echo file $i is empty
fi
done
for□i□in□$*
do
if □!□-s□$i
then
echo file $i is empty
fi
done
foreach□i□(□$*□)
if (□-z□$argv[i]□) then
echo file $argv[i] is empty
endif
end
※ switch结构
switch ( 变量 )
case 情况1: 语句组; breaksw
case 情况2: 语句组; breaksw
…….
default: 语句组
endsw
请比较以下shell程序:
B Shell和Bash
C Shell
for□i□in□$*
do
case□$i□in
*.c) echo $i is a C file ;;
*.o) echo $i is an OBJ file ;;
*) echo $i is an other file ;;
esac
done
foreach□i□(□$*□)
switch□(□$i□)
case *.c: echo $i is a C file
breaksw
case *.o: echo $i is an OBJ file
breaksw
default: echo $i is an other file
endsw
end
※ while结构
while ( 表达式 )
语句组
End
请比较以下shell程序:
B Shell
Bash
C Shell
n=0
while□[□$#□-gt□0□]
do
n=`expr□$n□+□1`
shift
done
echo n = $n
n=0
while□$#□-gt□0
do
let “n = n + 1”
shift
done
echo n = $n
set□n=0
while□(□$#argv□>□0□)
@□n□=□$n□+□1
shift
end
echo n = $n
1.8.3 假名(别名)机制
假名(别名)是指在C shell中将已有的命令重新起名。
※ 设置假名的命令格式
alias [假名 [命令] ] 设置或者显示假名
unalias 假名 撤消假名
alias命令有以下三种使用形式:
alias 假名 命令 将命令起名为假名
alias 假名 显示假名所定义的值
alias 显示所有假名的值
※ 假名定义示例
熟悉DOS命令的用户希望使用UNIX命令时,也能够使用与DOS一样的命令,因此可以给一些常用的UNIX命令起一个假名,例如:
% alias md mkdir 表示用md代表mkdir
% alias dir ls -l
% alias rd rmdir
% alias type cat
% alias edit vi
※ 假名应用示例
例如,显示ls的假名:
% alias ls
ls -CF 假设这是管理员预先定义的假名
取消ls原有的假名:
% unalias ls
% alias ls 原定义的假名消失
%
重新给ls起名:
% alias ls “ls -a” 使ls命令可以显示隐含目录/文件
% alias ls
ls -a
假名可以组合,例如:
% alias cd “cd ; pwd” 定义假名为组合命令
% alias cd 显示假名
cd ; pwd
% cd
/mnt/eejm/me00 显示注册目录
※ 在配置文件中设置假名
对一个用户来说,总是希望根据自己的喜好定义一些假名,而且以后一直可以使用。因此,应该把所需要的假名在配置文件中进行定义,这样每次登录时配置文件被运行后,假名生效。通常有两种做法:
⊙ 在~/.cshrc中增加所需要的alias命令
例如,用vi在~/.cshrc中增加以下alias命令:
alias sc “source ~/.cshrc”
alias vc vi ~/.cshrc 可以加引号,也可以不加引号
退出vi后执行
% source ~/.cshrc
然后,可以执行命令:
% vc 等价为“vi ~/.cshrc”
% sc 等价为“source ~/.cshrc”
⊙ 增加一个配置文件~/.alias,写入所需要的alias命令。并且在配置文件~/.cshrc中增加以下语句:
if□[□-r□~/.alias□]□then
source□~/.alias 如果文件.alias存在则运行之
endif
则在每次登录时,~/.alias就会被自动运行一次, alias定义生效。
例如,用vi在~/.alias中写入以下alias命令:
alias sa source ~/.alias
alias va vi ~/.alias
alias sc source ~/.cshrc
alias vc vi ~/.cshrc
alias dir ls -l
alias md mkdir
alias rd rmdir
alias type cat
alias edit vi
如果希望定义的alias立即生效,而不是在下一次登录时才生效,则应在退出vi后执行:
% source ~/.cshrc
1.8.4 命令史机制
※ 命令史定义
C shell设置了一个命令缓冲区(存储空间),记录先前执行过的命令,并且提供了显示和引用这些命令的功能,称为命令史机制。
【注】命令史是C shell和Bash都提供的功能。
与命令史相关的环境变量为history,即显示命令的数量。相关命令为history,用以显示history条先前执行过的命令。
为了便于理解,在配置文件中增加语句“set prompt=[\!]>”,表示将待命符设置为“[命令号]>”,其中特殊变量“!”表示当前命令的序号(命令号)。
执行以下命令:
[5]> 当前命令号为5
[5]> set history=6 设置命令记录数为6
[6]> history 显示命令史栈中的内容
1 ls -l
2 cat main.c
3 vi main.c
4 cc -c main.c
5 set history=6
6 history
[7]>
※ 命令史引用示例
假定设置命令history的假名为h,即已有定义为:
alias h history
则执行命令:
[7]> h 显示命令史栈
2 cat main.c
3 vi main.c
4 cc -c main.c
5 set history=6
6 history
7 h
[8]>
(1) 使用命令号引用栈中的命令
格式为: !n n表示需要引用命令的命令号
[8]> !1 使用命令号引用并执行第1条命令ls -l
ls -l
.......执行命令ls -l
[9]> !-2 用相对命令号引用前第2条命令(7)h
h
4 vi main.c
5 cc -c main.c
6 history
7 h
8 ls -l
9 h
[10]>
(2) 重复前一条命令
格式为: !!
[10]> !!
h
5 cc -c main.c
6 history
7 h
8 ls -l
9 h
10 h
(3) 使用前导匹配字符
格式为: !xxx xxx为需要匹配的字符串
[11]> !c 匹配到最近以c为字首的命令cc
cc -c main.c
[12]> !ca 匹配到最近以ca为字首的命令cat
cat main.c
[13]>
(4) 显示某条命令,但不执行
格式为: :p
[13]> !ca:p 显示以ca为字首的命令,但不执行
cat main.c
[14]>
(5) 修改上一命令中的内容后执行
格式为: ^匹配的字符串^新的字符串[^]
[14]> ^main^../tst/try^ 将上条命令的main改为../tst/try
cat ../tst/try.c 将cat main.c改为cat ../tst/try.c
[15]>
(6) 引用以前命令的某个命令行参数
格式为: :nn nn为参数的序号
[15]> ls main.c try.c
main.c try.c
[16]> cc -c !!:2 引用上条命令的第2个参数try.c
cc -c try.c
[17]>
(7) 引用前一命令的全部参数
格式为: !*
[17]> !15:p 显示第15条命令
ls main.c try.c
[18]> cp !* ../tmp 引用上条命令的全部参数:main.c try.c
cp main.c try.c ../tmp
[19]>
(8) 引用前一命令的最后一个参数
格式为: !$
[19]> ls !$ 引用上条命令的最后一个参数:../tmp
ls ../tmp
[20]>
作 业
※ 习题 (C shell、目录栈) E-7:1-23.2,1-23.4
※ 上机及习题: (C shell) E-5:1-22.1,1-22.2,1-22.4,1-22.5,1-22.6
※ 上机及习题 (C程序:映象文件及内存的大小) 2-19
附录B B Shell、Bash和C Shell的比较一览表
比较内容
B Shell (UNIX)
Bash (Linux)
C Shell (UNIX)
※ 基本特点
⊙ 命令分隔符
;
;
;
⊙ 续行符
\
\
支持用“\”续行,但不能把命令断开
⊙ 命令组
( )
( )
( )
⊙ 标准输入输出
stdin、stdout、stderr
stdin、stdout、stderr
stdin、stdout、stderr
⊙ 改变stdin定向
< file
< file
< file
⊙ 改变stdout定向
> file
> file
> file
⊙ 附加stdout定向
>> file
>> file
>> file
⊙ 改变stderr定向
2> file
2> file
>& file
⊙ Here Document
<< 分界符
<< 分界符
<< 分界符
⊙ 管道(流水线,pipe line)
|
|
|
⊙ 文件名的通配符
星号“*”,问号“?”,一对方括号“[...]”
星号“*”,问号“?”,一对方括号“[...]”
星号“*”,问号“?”,一对方括号“[...]”
⊙ 特殊字符
;、(、)、&、<、>、|、*、?、[、]、#、
$、``、~、”、’、\
※ 变量
⊙ 变量定义 禁止空格
变量=值 等号两侧禁止空格
变量=值 等号两侧禁止空格
set□变量=值
例:
x=finish
x=finish
set□x=□finish
⊙ 引用变量
$变量 或者 ${变量}
$变量 或者 ${变量}
$变量 或者 ${变量}
⊙ 撤消定义
变量=
变量=
set□变量=
⊙ 删除变量
不提供
unset 变量
unset 变量
⊙ 环境变量
通常用大写字母表示
通常用大写字母表示
通常用小写字母表示
⊙ 注册目录
HOME
HOME 或者 ~
HOME 或者 ~
⊙ 可执行路径
PATH
PATH
path
⊙ 待命符
PS1 PS2
PS1 PS2
prompt
⊙ 定义环境变量
环境变量=值 等号两侧禁止空格
export 环境变量
环境变量=值 等号两侧禁止空格
export 环境变量
setenv□环境变量 值
⊙ 显示环境变量
echo $环境变量
echo $环境变量
echo $环境变量 或者
printenv□$环境变量
※ 特殊变量
⊙ 进程号
$$
$$
$$
⊙ 进程状态值
$?
$?
$?
※ Shell环境的识别
⊙ 配置文件
.profile
.bashrc,.bash_profile
.cshrc,.login
⊙ 执行配置文件
. 配置文件
. 配置文件
source 配置文件
⊙ Shell程序首行
#! /bin/sh 或者 非注释行
#! /bin/bash
#! /bin/csh 或者 非#! /bin/sh的注释行
※ 输入输出语句
⊙ 输入语句
read 变量
read 变量
set 变量=$<
⊙ 输出语句
echo 变量或字符串
⊙ 输出不换行
echo ......\\c
echo- n ……
echo- n ……
※ 运算语句
变量=`expr表达式` 等号两侧禁止空格
变量=`expr表达式` 等号两侧禁止空格
@□变量 = 表达式
let “变量 = 表达式”
※ 输入变量和程序变量
⊙ 命令名本身
$0
$0
$0或者$argv[0]
⊙ 第一个参数
$1
$1
$1或者$argv[1]
⊙ 第二个参数
$2
$2
$2或者$argv[2]
⊙ 第三个参数
$3
$3
$3或者$argv[3]
⊙ 参数的个数
$#
$#
$#argv
⊙ 全体参数
$*
$*
$*或者$argv
⊙ 变量是否定义
不提供
不提供
变量未定义:$?变量 为0
变量已定义:$?变量 为1
⊙ 数组定义
不提供
不提供
set 数组名=(a1 a2 ...)
⊙ 数组元素
不提供
不提供
$数组名[1], $数组名[2], ...
⊙ 数组元素的个数
不提供
不提供
$#数组名
⊙ 数组是否定义
不提供
不提供
数组未定义:$?数组名 为0
数组已定义:$?数组名 为1
※ 运算符和表达式
⊙ 算术运算符
+、-、*、/、%
+、-、*、/、%
++、--、**
+、-、*、/、%
++、--、**
⊙ 移位运算符
不提供
<<、>>
<<、>>
⊙ 关系运算符(数值比较)
-lt、-gt、-le、-ge、-eq、-ne
-lt、-gt、-le、-ge、-eq、-ne
<, >, <=, >=, ==, !=
⊙ 逻辑运算符
-a、-o、!
-a、-o、!
&&、||、!
⊙ 按位运算符
不提供
&、|、~、^
&、|、~、^
⊙ 复合赋值符
不提供
+=、-=、*=、/=、%=
<<=、>>=、&=、^=、|=
+=、-=、*=、/=、%=、^=
(<<=、>>=、&=、|=不支持)
⊙ 条件运算符
不提供
? :
不提供
⊙ 表达式
[□表达式□] 或者 test□表达式
[□表达式□] 或者 test□表达式
(□表达式□)
⊙ 在命令行使用表达式
不提供
可在命令行独立使用
不提供
⊙ 字符串测试表达式
s1□=□s2 字符串s1与s2相同
s1□=□s2 字符串s1与s2相同
s1□==□s2 字符串s1与s2相同
s1□!=□s2 字符串s1与s2不相同
s1□!=□s2 字符串s1与s2不相同
s1□!=□s2 字符串s1与s2不相同
-z□s s是空字符串
-z□s s是空字符串
-z□s s是空字符串
-n□s s是非空字符串
-n□s s是非空字符串
-n□s s是非空字符串
⊙ 文件判断测试表达式
-r□file 文件file存在且可读
-r□file 文件file存在且可读
-r□file 文件file存在且可读
-w□file 文件file存在且可写
-w□file 文件file存在且可写
-w□file 文件file存在且可写
-x□file 文件file存在且可执行
-x□file 文件file存在且可执行
-x□file 文件file存在且可执行
-d□file file存在且是目录
-d□file file存在且是目录
-d□file file存在且是目录
-s□file 文件file存在且非空
-s□file 文件file存在且非空
-e□file 文件file存在且非空
-f□file file为普通文件且存在
-z□file file为空文件
-h□file file为符号连接文件
-o□file file为本用户所拥有
file1□-nt□file2 文件file1比file2新
file1□-ot□file2 文件file1比file2旧
⊙ 其他语句
break
continue
goto 语句标号
break
continue
goto 语句标号
break
continue
goto 语句标号
※ 控制结构及相关语句
⊙ if 结构
if□ [□表达式□]
then
语句组
else else可以省略
语句组
fi
If□[ □表达式□];
then
语句组
elif □[□表达式□];
then
语句组
else
语句组
fi elif和else可以省略
if (□表达式□)□then
语句组
else if(□表达式□)□then
语句组
else
语句组
endif
else if和else可以省略
⊙ for 结构
for□索引变量□in□变量表
do
语句组
done
for□索引变量□in□变量表
do
语句组
done
foreach□索引变量□(□变量表□)
语句组
end
⊙ switch 结构
case□变量□in
情况1) 语句组 ;;
情况2) 语句组 ;;
…….
*) 语句组 ;;
esac
case□变量□in
情况1) 语句组 ;;
情况2) 语句组 ;;
…….
*) 语句组 ;;
esac
switch□(□变量□)
case□情况1: 语句组; breaksw
case□情况2: 语句组; breaksw
…….
default:
语句组;
endsw
⊙ while 结构
while□[□表达式□]
do
语句组
done
While□[□表达式□]
do
语句组
done
while□(□表达式□)
语句组
end
⊙ until 结构
不提供
until□[□表达式□]
do
语句组
done
不提供
⊙ 移位语句
shift
shift
shift
※ 命令行编辑
不提供
有
不提供
※ 假名(别名)机制
不提供
不提供
alias、unalias
※ 命令史机制
不提供
有
有
※ 工作目录栈
不提供
pushd、popd
pushd、popd
※ 函数
⊙ 函数定义
[function]□函数名□()
{
语句
}
[function]□函数名□()
{
语句
}
不支持
⊙ 函数调用
函数名
⊙ 函数形参
$#,$*,$1,$2,...
⊙ 函数外部调用
.□shell文件 含有函数的文件
⊙ 删除函数
unset□函数名
⊙ 显示函数
set
展开阅读全文