quickleader 2004-5-26 22:37
shell programming
Shell
当我们登入 Linux 之後, 第一个接触到的, 便是 Shell. 我们必须对它有点初步的认识才行.
一. Shell 简介.
Linux 系统分成三个重要的部份
核心
Shell
工具程式
核心的部份相当低阶, 操作者不易和它直接沟通, 因此, 必须要有一个友善的介面(interface), 使得操作时能更为方便, 这个介面便是 Shell.
换言之, Shell 就是一个居於核心和操作者之间的一层使用者介面.
那麽, 为何称它为 Shell 呢? Shell 的本意是 "壳" 的意思呢!
没错, 在核心的外面, 包覆着一层外壳, 用来负责接收使用者输入的指令, 然後将指令解译成核心能够了解的方式, 传给核心去执行, 再将结果传回至预设的输出周边.
如图所示:
例如: 键入
ls -l
shell 给你以下回应:
拥
档 有
案 档
种 案 档案大小 最近修改的
类 档案权限 数 拥有人 组别 (byte单位)日期及时间 档案名称
drwxr-xr-x 14 root root 1024 Jul 21 21:31 .
drwxr-xr-x 17 root root 1024 Apr 11 12:01 ..
drwxr-xr-x 8 82 82 1024 Feb 25 19:23 apache
-rw-r--r-- 1 root root 1335460 Feb 25 17:45 apache_1_3_4.tar.gz
drwxr-xr-x 6 root root 1024 Aug 31 1998 ftp
drwxr-xr-x 5 root root 1024 Aug 31 1998 httpd
drwx------ 2 james james 1024 Apr 23 06:47 james
drwxr-xr-x 2 root root 12288 Aug 31 1998 lost+found
drwxr-xr-x 2 msql nobody 1024 Dec 28 1998 msql
drwxr-xr-x 28 ols3 ols3 2048 Jul 19 21:38 ols3
drwxr-xr-x 3 1022 nobody 1024 Jan 25 23:40 ols3cgi
drwxrwxr-x 3 perl ols3 1024 Feb 2 07:11 perl
-rw------- 1 root root 2097152 Jul 21 18:39 quota.group
-rw------- 1 root root 1278656 Jul 21 18:39 quota.user
drwxrwxr-x 2 root nobody 1024 May 11 1998 samba
drwxr-xr-x 3 apache nobody 1024 Feb 25 16:58 temp
drwxrwxr-x 2 webadm nobody 1024 Mar 14 16:34 webadm
其实不只是 Linux 有这一层 Shell, 其它作业系统也有.
比如 DOS 的 command.com, Windows 的 GUI(Graphical User Interface), Mac 的 GUI.
Shell 按着表现的方式与读取使用者输入种类的不同, 可分为二大类:
Text base : 文字导向
Graph base: 图型导向
所谓 "读取使用者输入种类不同" 是指: 读取自键盘, 或读取自滑鼠, 其它 serial input, 萤幕触控等.
这样说来, Shell 好像只是命令直译器罢了?!
嗯, 这倒要按不同的 OS 所附给的 Shell 其功能和选择性的自由度而定.
以 DOS 的 COMMAND.COM 而言, 它就是一个十足的命令直译器, 除了一点点 batch 档的能力之外, 它的功能并不多. Win 平台的 GUI, 则是一个图型式的命令直译器, 介面十分友善. 不过, 这二种 OS, 不能让你自由而简单地选择 Shell.(以前 DOS 有 4dos 可选用)
Linux 的 shell, 除了做为命令直译器之外, 它也是一个不错的程式语言, 是系统管理维护时的重要工具.
由於 Unix 家族, 对 Shell 的处理, 采独立自由开放的方式, 因此, Shell 的种类相当地多, 更可以让人自由地更换(chsh).
目前流行的 shell 有:
Bourne shell : sh
C shell : csh
Korn shell: ksh (商业软体)
tcsh (free)
Bourne Again shell: bash (GNU)
Linux 的标准 shell 是采用 bash. 它也是我们要学习的主要对象.
二. Shell 的简史
第一个重要的 shell 是 Bourne shell (如此命名是为了纪念此 shell 的发明者 Steven Bourne), 1979 年第一个流行的 Unix 版本 7 发行时, 开始使用 Bourne shell.
Bourne shell 的主档名为 sh, 因此, 日後人们便以 sh 为 Bourne shell 的主要识别名称.
虽然 Unix 上的 shell 有许多种, 但 Bourne shell 的地位至今仍然没有改变. 许多 Unix 系统中仍然使用 sh 做为重要的管理工具. (它的工作从开机到关机, 几乎无所不包)
第一个广为流行使用的 shell 变种是 C shell. C shell 主要附在 BSD 版的 Unix 系统中. 它的作者是柏克莱大学的 Bill Joy. C shell 主要是因为其语法和 C 语言相类似, 因而得名. 这使得 Unix 系统的程式师, 在学习 C shell 时, 感到相当地方便容易.
以上这二种形成 shell 的二大主流, 後来的变种 shell 大都攫取这二种 shell 的优点.
比如 Korn, tcsh 及 bash.
Bash shell 是 GNU 计划的重要工具软体之一, 也是 GNU 作业系统中标准的 shell.
Bash 相容於 sh, 因此, 许多早期开发出来的 Bourne shell 都可以继续在 bash 中运作. 现在我们安装好的 RedHat Linux 便是完全使用 Bash. (/bin/sh -> /bin/bash)
Bash 在 1988 年诞生, 最初的作者是 Brian Fox, Chet Ramey 於 *** 加入, 现在官方正式的维护者是 Chet Ramey, 他的工作便是持续不断地增强 bash 的功能.
1995~1996 期间推出 bash 2.0 , 在这之前, 广为使用的版本是 1.14.x, 它增加了许多新的功能, 以及更好的相容性.
当然, Bash 是完全免费的, 它是 Open Source 的一员, 原始码全部开放.
二. Bash 的功能.
Bash 具有以下功能:
相容於 Bourne shell (sh)
包含有 C shell 以及 Korn shell 中最好的功能.
具命令列编修的能力(您记得以前 DOS 中的 doskey 吗?)
工作控制(job control)的能力, 可控制前景及背景程式
具 shell 程式设计的能力, 可让您自订shell及设计程式, 管理系统.
三. 新版的 Bash 哪里抓取?
若欲抓取新版的 bash, 可至 <!-- CETagParser ~url
<a href="http://www.gnu.org" target=_blank>http://www.gnu.org<!-- CETagParser ~/url
</a> 或其 mirror 站台.
中研院 FTP 也是不错的选择. [url=ftp://ftp.sinica.edu.tw[/url] 或 [url]ftp://linux.sinica.edu.tw]ftp://ftp.sinica.edu.tw[/......ftp://linux.sinica.edu.tw[/url]
三. 开始使用 Bash
当你 login 进 Linux 主机时, 便开始和 bash 互动, 一直到你 logout 主机(下exit,logout,或按^D) 为止.
Bash 的提示符号为 $ (代表一般身份使用者), 当您具有 root 权限时, 提示符号则变为 #.
一旦出现提示符号时, 您便可以开始键入操作命令列(command line)了.
命令可分为二大类:
bash 内建的指令
程式
如果是 bash 内建的指令, 则由 bash shell 负责回应; 若是程式, 则 shell 会找出该程式, 然後将控制权交给核心, 由核心执行该程式, 执行完之後, 再将控制权交回给 shell.
怎麽知道那些指令是 bash 内建的, 那些是程式呢? 通常用 "which 指令", 若没有任何回应, 表示是内建的指令(除非该指令错误、不存在, 或该程式不在预设的搜寻路径之内), 例如下:
[ols3@ols3 /ols3]$ which echo [没有回应, 表示是内建的指令]
[ols3@ols3 /ols3]$ which ls
/bin/ls
四. 命令列的格式.
命令列通常由好几个字串组成, 中间用空白或 tab 键分开. 如下所示:
command options arguments(或称为 parameters)
命令 选项 参数
rm -rf /home/ols3
除了空白和 tab 键之外, 每一部份, 我们称之为 token, 比如上面的例子中, 便有三个 token: rm, -rf, /home/ols3.
当键入此一命令列时, shell 首先将它分解成个别的 token, 然後判断是内建的指令, 或是程式, 再按之前提过的方式去执行.
怎麽知道一个命令或程式, 它有那些选项和参数呢? 通常 man 一下该指令, 就可以得到了. 例如:
man rm
另外, 多行指令也可以一下全部写在同一命令列中, 只要中间用 ; 分开, 如:
ls ; mkdir test ; clear
五. 现行目录和自家目录.
所谓现行目录(current directory)是指: 你现在所处的位置, 又称为工作目录(working directory).
欲知现行目录为何? 可下 pwd 指令便知.
所谓自家目录(home directory)是指: 当初 root 为你建立帐号时, 所指定给你的一个私人专用的目录, 也是你登入系统之後, 第一个进入的地方.
欲知自家目录, 可用下列方式:
cd (然後直接按 Enter)
cd ~ (~ 代表自家目录)
cat /etc/passwd | grep 您的帐号
相关的技巧
cd ./myway (进入目前目录下的 myway 目录中)
cd .. (回到上一层目录)
cd - (回到先前的目录)
六. 万用字元.
如果命令列的参数中, 含有档名, 那麽万用字元(wildcards)可以带来十分便利的操作. (不过若使用不当, 也是恶梦的开始)
如果各位以前有过 DOS 的操作经验, 应该还记得 * 及 ? 所代表的意义吧?!
以下是 bash 中使用的万用字元:
? 代表任何单一字元(character)
* 代表任何字串 (注意: 0 个以上的字元, 例: *yes 将包含 yes 或 yes-or-not)
[字元组合] 在中括号中的字元皆符合, 如: [a-z]代表所有的小写字母
[!字元组合] 不在中括号中的字元皆符合, 如: [!0-9]代表非数字的字元皆符合
七. 输入和输出与重新导向.
当 Linux 系统完成开机之後, 预设上, 便开有三个档案, 这三个档案是做为输入、输出以及显示错误之用的.
我们称之为:
标准输入: 通常是键盘, 档案代码为 0
标准输出: 通常是萤幕, 档案代码为 1
标准错误: 通常标准输出相同(也就是萤幕), 档案代码为 2
虽然系统已帮你设好了这三个档案, 但我们仍然可以视需要, 适时地改变输入,输出,及错误这三者至不同的地方. 这种改变标准输出入的动作, 我们称之为 "I/O 重新导向" (I/O Redirection).
例如:
ls -la > myfile 就是将查询的结果重新导向至 myfile 中(本来是应该出现在萤幕上的)
cat myfile 便可以看见 ls -la 的结果.
cat < myfile > youfile 就是将 myfile 的内容拷贝给 youfile.
> 代表将输出转向
< 代表将输入转向
另一个会将输出入转向的机制是 "管线" (Pipelines).
所谓的管线就是将一个程式的输出当成另一个程式的输入.
例如: cat /etc/passwd | grep ols3
上面这段指令的意思是说: 把 /etc/passwd 档的内容显示结果(即输出) 丢给 grep 这个指令当作输入值, 然後由 grep 从中找出包含关键字 ols3 的资料列.
八. 前景与背景工作.
Linux 是多人多工的作业系统, 这意谓 Linux 可以让多人同时使用, 更可以同时执行许多程式.
一般而言, 你所执行的指令会一直握着控制权, 一直到程式结束为止, 我们称为这样的执行工作是在前景工作(foreground jobs), 如果, 执行指令时, 你仍然可以再做其它的事情, 那我们就称它是在背景工作.
通常比较耗时间的工作, 我们会把它丢到背景去执行, 而这期间, 我们仍然可以和 shell 继续沟通, 下达其它命令给 shell 去执行.
例如: 我们想从中研院的 FTP 伺服器下载某一个目录中所有的档案, 但又不想等它执行完毕(因为这样耗时间,也很无聊), 可以用以下的方式来达成:
ncftp -R <!-- CETagParser ~url
<a href="ftp://linux.sinica.edu.tw/pub1/redhat/powertools" target=_blank>ftp://linux.sinica.edu.tw/pub1/redhat/powertools<!-- CETagParser ~/url
</a> &
其中 & 这个符号便是将命令列丢到背景去执行的指令.
如果您想离线之後, 仍然令系统继续传档, 可以在前面再加一个 nohup 的指令, 如下:
nohup ncftp -R <!-- CETagParser ~url
<a href="ftp://linux.sinica.edu.tw/pub1/redhat/powertools" target=_blank>ftp://linux.sinica.edu.tw/pub1/redhat/powertools<!-- CETagParser ~/url
</a> &
nohup 是 no hangup 即不挂断之意.
八. 特殊字元及引号.
有许多字元, 对 shell 来说, 是具有特殊意义的. 详列於下:
符号 意义
~ 自家目录
` 命令取代
# 解
$ 变数取值
& 背景工作
* 万用字元
( 子shell开始
) 子shell结束
\ 使特殊字元恢复本意
| 管线
[ 字元组合开始
] 字元组合结束
{ 命令区块开始
} 命令区块结束
; 命令分隔号
' 单引号(不具变数置换的功能)
" 双引号(具置换的功能)
< 输入转向
> 输出转向
/ 路径分隔号
? 万用字元
! 管线逻辑意义上的 NOT
九. 常用控制组合键.
我们在操作 Linux 时, 常会使用一些组合键来控制 shell 的活动.
详列如下:
组合键 意义
Ctrl - C 中止目前的命令
Ctrl - \ 同上
Ctrl - D 输入结束, 即 EOF 之意 (如使用 mail 信件结束时); 或 logout 登出 Linux
Ctrl - Z 暂停目前的命令
Ctrl - M 相当按 Enter
Ctrl - S 暂停萤幕输出
Ctrl - Q 恢复萤幕输出
Ctrl - U 将命令列整列删除
Ctrl - ? 删除最後一个字元, 相当於按 Del
十. 指令练习.
指令 选项或参数 意义
ls
pwd
which
more
less
passwd
man
cat
touch
cd
mkdir
rmdir
cp
rm
head
tail
wc
grep
ps
quickleader 2004-7-16 16:57
Re:shell programming
Linux程式设计-11.Shell Script(bash)--(11)参数与变数
<!-- CETagParser ~url
<a href="http://www.openchess.org/noitatsko/programming/" target=_blank>http://www.openchess.org/noitatsko/programming/<!-- CETagParser ~/url
</a> (2001-05-25 18:08:00)
在继续下去介绍function之前,我们必须停下来介绍"参数与变数"。
--------------------------------------------------------------------------------
参数(Parameters)是用来储存"值"的资料型态,有点像是一般语言中的变数。它可以是个名称(name)、数字(number)、或者是以下所列出来一些特殊符号(Special Parameters)。
在shell中,变数是由name形式的参数所构成的。
--------------------------------------------------------------------------------
在前面的许多例中,我们事实上已经看到许多参数的运用。要设定一个Parameter实际很简单:
name=value
例如说:
MYHOST="foxman"
而要使用它时,则是加个"$"符号。
echo $MYHOST
--------------------------------------------------------------------------------
位置参数(Positional Parameters)
--------------------------------------------------------------------------------
所谓的位置参数便是0,1,2,3,4,5,6,7,8,9...。使用时,用$0,$1,$2...。
位置参数是当script被载入时,後面所附加的参数。$0是本身,$1则为第一个参数,$2为第二个,依此类推。而当Positional Parameters被function所使用时,它们会被暂时取代(下一节会介绍function)。
例如以下这个script:
#!/bin/sh
# Filename : position
echo $0
echo $1
执行时:
[foxman@foxman bash]# ./position abc
./position
abc
当位置参数超过两位数时,有特别的方法来展开,称为Expansion。
--------------------------------------------------------------------------------
特殊参数(Speical Parameters)
这些符号,非常不人性,对新手来说很困扰。但上手後,会觉得方便无比,有些如果您看不懂的话,就--算了,不用浪费太多时间在上面。
--------------------------------------------------------------------------------
* 星号
将Positional Parameters合成一个参数,其间隔为IFS内定参数的第一个字元(见内建变数一节)。
例:
#!/bin/sh
# starsig
echo $*
执行:
[foxman@foxman bash]# starsig a b c d e f g
a b c d e f g
--------------------------------------------------------------------------------
@ at符号
与*星号类同。不同之处在於不参照IFS。
例:
#!/bin/sh
# atsig
echo $@
执行:
[foxman@foxman bash]# atsig a b c d e f g
a b c d e f g
--------------------------------------------------------------------------------
# 井字号
展开Positional parameters的数量。
例:
#!/bin/sh
# poundsig
echo $#
执行
[foxman@foxman bash]# poundsig a b c d e f g
7
--------------------------------------------------------------------------------
? 问号
最近执行的foreground pipeline的状态。
--------------------------------------------------------------------------------
- 减号
最近执行的foreground pipeline的选项参数。
--------------------------------------------------------------------------------
$ 钱钱钱
本身的Process ID。
[foxman@foxman bash]# ps ax | grep bash
1635 p1 S 0:00 /bin/bash
[foxman@foxman bash]# echo $$
1635
--------------------------------------------------------------------------------
! 惊号
最近执行背景命令的Process ID。
--------------------------------------------------------------------------------
0 零
在Positional Parameters一部份已经说明过了,是执行的shell script本身。但如果是用"bash -c",则$0被设为第一个参数。
[foxman@foxman bash]# echo $0
/bin/bash
--------------------------------------------------------------------------------
_ 底线符号
显示出最後一个执行的命令。
[foxman@foxman bash]# echo $_
bash
--------------------------------------------------------------------------------
内建变数(Shell Variables)
Bash有许多内建变数,像PATH、HOME、ENV......等等。这些内建变数将在另一节中,专门一一说明。
quickleader 2004-7-16 16:59
Re:shell programming
Linux程式设计-11.Shell Script(bash)--(13)Bash内建指令集
<!-- CETagParser ~url
<a href="http://www.openchess.org/noitatsko/programming/" target=_blank>http://www.openchess.org/noitatsko/programming/<!-- CETagParser ~/url
</a> (2001-05-25 20:10:00)
Bash内建指令集
以下的命令,大部份都没有使用例,您可能会看不出所以然,摸不着头脑。在我加入例说明前,建议您"man bash",然後自己实际操作一次。
--------------------------------------------------------------------------------
: [arguments]
不做任何事,除了[arguments]一些参数展开及一些特定重导向的作业外。
永远返回零。它的用法跟true一样。
--------------------------------------------------------------------------------
. filename [arguments]
source filename [arguments]
由filename中读取命令,并执行。
您会在/etc/rc.d/*中发现很多
. /xxxx
的指令,而xxxx的permission都不是可执行的。事实上,在tcsh中,需要用
source /xxxx
来做同样的指令。
注意到"."的後面是有空格的(比较一下". /"跟"./",不一样)。filename是内含指令的纯文字档即可,无须chmod 755 filename。
例
filename : my_source
DEV=lo
IP=127.0.0.1
NETMASK=255.0.0.0
BROADCAST=127.255.255.255
ifconfig $IP netmask $NETMASK broadcast $BROADCAST dev $DEV
接下来
. my_source
或
source my_source
便可执行该script,而不需要"chmod 755 my_source"
--------------------------------------------------------------------------------
alias [name[=value] ...]
昵称命令
例如您如果来自DOS的世界,对UNIX的指令不习惯,可用alias来修改,以符合您的习惯。
例
alias ls="ls --color"
alias dir="ls"
alias cd..="cd .."
alias copy="cp -f" # dangerous, recommend, "cp -i"
alias del="rm -f" # dangerous, recommend, "rm -i"
alias move="mv -f" # dangerous, recommend, "mv -i"
alias md="mkdir"
alias rd="rmdir"
--------------------------------------------------------------------------------
unalias [-a] [name ...]
unalias取消alias的设定。"unalias -a"将全部alias取消。
例
unalias copy
--------------------------------------------------------------------------------
bg [jobspec]
将指定任务放到背景中,如果jobspec未指定,内定为目前的。
--------------------------------------------------------------------------------
fg [jobspec]
将指定任务放到前景中,如果jobsepc没有指定,那麽内定为目前的。
--------------------------------------------------------------------------------
jobs [-lnp] [ jobspec ... ]
第一种形式列出目前正在工作的任务。
-l : 除了列出一般资讯外,还列出Process IDs。
-p : 仅列出该工作群"首脑"(Process group leader)的Process ID.
-n : 则仅列出有改变的jobs的状态。
如果给定jobspec,输出资讯则只有该jobspec。
返回值为零,除非有非法的选项发生。
jobs -x command [ args ... ]
如果使用第二种形式(-x),jobs取代指定的command及args,并执行返回其Exit Status。
--------------------------------------------------------------------------------
kill [-s sigspec | -sigspec] [pid | jobspec] ...
将sigspec的信号送到pid或jobspec。
sigspec可以是SIGKILL/KILL这种形式或是信号号码。如果sigspec是signal name,则大小写无关,而且可以没有SIG。
kill -l [signum]
列出信号名称。
[foxman@foxman bash]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGIOT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR
--------------------------------------------------------------------------------
wait [n]
等待指定的行程,并返回其结束状态。n可以是个jobspec或Process ID。如果n未指定,则等待所有的子行程,及返回值为零。若n为不存在的job或process,则返回127。否则,返回值为最後一个job/process的Exit Status。
--------------------------------------------------------------------------------
bind [-m keymap] [-lvd] [-q name]
bind [-m keymap] -f filename
bind [-m keymap] keyseq:function-name
显示出目前readline的按键及链结函数设定或是巨集。
-m keymap : 设定keymap binding。
-l : 显示出所有readline function的名称。
-v : 显示出目前的function name及bindings。
-d : 显示出function name及bindings。
-f filename : 从filename读取key bindings。
-q function : 询问那个按键触发function。
--------------------------------------------------------------------------------
break [n]
跳出控制回圈for/while/until中使用。如果有指定n,则跳出n层。n必须是大於等於1。若n大於巢状圈数,则所有的圈都会跳离。返回值回零。
--------------------------------------------------------------------------------
continue [n]
还原控制回圈for/while/until中使用。如果有指定n,则返回n层。n必须是大於等於1。若n大於巢状圈数,则还原到最上层。返回值回零。
--------------------------------------------------------------------------------
exit [n]
离开程式。n是Exit Status。
--------------------------------------------------------------------------------
return [n]
在function中使用。n为返回值,其作用与Exit Status一样。
--------------------------------------------------------------------------------
builtin shell-builtin [arguments]
执行内建函数。当您定义了与内建函数相同的指令时,可用此命令来执行内建函数。
--------------------------------------------------------------------------------
cd [dir]
更换目录到dir。如果没有指定,内定为HOME所指定的目录。
--------------------------------------------------------------------------------
command [-pVv] command [arg ...]
用command指定可取消正常的shell function寻找。只有内建命令及在PATH中找得到的才会被执行。"-p"选项,搜寻命令的方式是用PATH来找。"-V"或"-v"选项,会显示出该命令的一些简约描述。
--------------------------------------------------------------------------------
declare [-frxi] [name[=value]]
typeset [-frxi] [name[=value]]
宣告参数并给它们设定属性。如果没有给定名称,将会显示各参数值。
-f : 仅使用函数名称。
-r : 将name设为readonly。
-x : 将name输出给後续环境使用。
-i : 该参数被设为integer来使用,可用於算术表述。
用"+"时,关闭该属性。
--------------------------------------------------------------------------------
dirs [-l] [+/-n]
显示目前记忆的目录。目录可透过pushd/popd来操作。
+n : 显示开始的记录n个。
-n : 显示结尾的记录n个。
-l : 显示较多的资讯。
--------------------------------------------------------------------------------
echo [-neE] [arg ...]
输出显示args,由空白分隔。返回值永为零。
-n : 不跳行。
-e : 启动"\"符号的解译。
-E : 将ESC解译功能取消。
"\a" : alert(bell),发出声响。
"\b" : backspace,倒退。
"\c" : suppress trailing newline,不跳行。
"\f" : form feed,跳行跳格。
"\n" : new line,新行。
"\r" : carriage return,回到行起点。
"\t" : horizontal tab,水平跳位。
"\v" : vertical tab,垂直跳位。
"\\" : 输出"\"。
"\nnn" : 输出ASCII Code号码nnn(八进位)。
--------------------------------------------------------------------------------
enable [-n] [-all] [name ...]
启动或关闭内建函数命令。使用"-n"将所有指定命令皆关闭,否则都是启动的。如果只有"-n"参数,它将会显示所有关闭的函数。如果只有"-all",它将会显示所有内建命令。
--------------------------------------------------------------------------------
eval [arg ...]
读取args,并将args合为一个命令,然後执行。其返回值成为eval的返回值。如果没有参数,eval返回True。
--------------------------------------------------------------------------------
exec [[-] command [arguments]]
当命令执行时,该命令取代shell,没有新的process产生。如果第一个参数是"-",shell会将"-"放入第零个参数,传给command。
--------------------------------------------------------------------------------
export [-nf] [name[=word]] ...
export -p
将name输出给环境,给往後的命令使用。"-f"选项表示name是函数。"-p"显示出所有export的名称。"-n"移除name。
--------------------------------------------------------------------------------
set [--abefhkmnptuvxldCHP] [-o option] [arg ...]
-a : 自动将变数标记为可让後面环境所使用。
-b : 立即报告被终结的背景程式状态。
-e : 当命令(simple-command,见後面)返回非零值时,立即跳出。
-f : 取消pathname expansion。
-h : 找出所记忆的函数命令位置。
-k : 所有keyword参数都放到环境中。
-m : 监督模式。
-n : 读取命令,但不要执行。可用於语法检查。
-p : 打开privileged模式。
-t : 当读取一个命令并执行後,立即离开。
-u : 当参数展开时,把unset参数当成是错误。
-v : 列出shell input lines。
-x : 在展开每个simple-command後,bash显示展开值在PS4上。
-l : 储存并还原name binding在for语法中。
-d : 关闭hasing command搜寻。
-C : 跟`noclobber=`一样。请见内定参数一节。
-H : 启动! style history substitution。
-P : 在使用像cd这种指令时,不要跟随symbolic links。
-- : "--"之後,没有参数跟在後面。
- : 指定将所有後面的参数当成是位置参数。
-o option-name : option-name可以是以下之一
allexport : 与"-a"相同。
braceexpand : 启动Brace Expansion。这是内定设定。
emacs : 使用emacs-style命令列编辑界面。
errexit : 与"-e"相同。
histexpand : 与"-H"相同。
ignoreeof : 效果跟`IGNOREEOF=10`一样。
interactive-commands : 允许#做为解。
monitor : 与"-m"相同。
noclobber : 与"-C"相同。
noexec : 与"-n"相同。
noglob : 与"-f"相同。
nohash : 与"-d"相同。
notify : 与"-b"相同。
nounset : 与"-u"相同。
physical : 与"-P"相同。
posix : Bash行为修改为Posix 1003.2标准。
privileged : 与"-p"相同。
verbose : 与"-v"相同。
vi : 使用vi-style命令列编辑程式。
xtrace : 与"-x"相同。
--------------------------------------------------------------------------------
unset [-fv] [name ...]
移除对映於name的参数。要注意PATH、IFS、PPID、PS1、PS2、UID、EUID不能unset。若RANDOM、SECONDS、LINENO、HISTCMD被unset,它们会丧失原有意义,既始它们後来被重设也一样。返回值为True,除非name是不能被unset的。
--------------------------------------------------------------------------------
fc [-e ename] [-nlr] [first] [last]
fc -s [pat=rep] [cmd]
修正命令。
--------------------------------------------------------------------------------
getopts optstring name [args]
解析位置参数。
--------------------------------------------------------------------------------
hash [-r] [name]
对每个name命令的完整路径记录下来。"-r"选项强迫忘记所有命令位置。如果没有给参数,则将会印出所有的资讯。返回值为True。
--------------------------------------------------------------------------------
help [pattern]
显示协助资讯。
--------------------------------------------------------------------------------
history [n]
history -rwan [filename]
没有参数时,会显示所下命令的历史记录。带有参数"n"则显示最後n个。
其它参数如下:
-a : 新增"新历史"到历史档中。
-n : 读取尚未读到历史中的记录。
-r : 读取filename做为历史档,并用它为目前历史记录。
-w : 将现有历史记录写到filename中。
--------------------------------------------------------------------------------
let arg [arg ...]
算术表述。请参考算术表述一节。
--------------------------------------------------------------------------------
local [name[=value] ...]
产生一个局部参数。如果用於function,则其作用围在function内及其子函数。
--------------------------------------------------------------------------------
logout
离开login shell。
--------------------------------------------------------------------------------
popd [+/-n]
移除目录堆叠。"+n"移除上面n个,"-n"移除下面n个。
--------------------------------------------------------------------------------
pushd [dir]
pushd +/-n
将目录新增到目录堆叠的最上面。"+n"旋转该堆叠,使第n个目录变成最上面。"-n"旋转该堆叠,使倒数第n个目录变成最上面。
--------------------------------------------------------------------------------
pwd
列出目前工作目录的绝对路径。
--------------------------------------------------------------------------------
read [-r] [name ...]
读进一行,然後第一个字设到第一个name,第二个设到第二个name,依此类推。如果没有name在参数中,则read会将值设到REPLY。返回值为零,除非遇到End-Of-File。若有"-r"选项,则"\n"被考虑为该行的一部份。
--------------------------------------------------------------------------------
readonly [-f] [name ...]
readonly -p
将给定的name标记为readonly。如果是"-f"选项,则函数也一样被标记为readonly。"-p"会列出所有readonly的name。"--"取消检查剩馀的参数。
--------------------------------------------------------------------------------
shift [n]
Positional Parameters从n+1...开始,会被改为$1...。n若为零,则没有改变。n若未给定,则内定为1。n必须是非负数,并且小於或等於$#。若n大於$#,则没有改变。返回值为零,除非n大於$#或小於零。
--------------------------------------------------------------------------------
suspend [-f]
暂停这个shell的执行,直到它收到SIGCONT信号。"-f"选项则是叫login shell不要抱怨,不过还是一样暂停。返回状态零,除非该shell是个login shell,而且没有"-f"选项。
--------------------------------------------------------------------------------
test expr
[ expr ]
我们在Exit Status的部份已经说过了,不再重。
--------------------------------------------------------------------------------
times
列出该shell的累积的使用者及系统时间及从shell执行的process时间,返回值为零。
--------------------------------------------------------------------------------
trap [-l] [arg] [sigspec]
当收到sigspec信号时,执行arg命令。"-l"显示出信号名称及号码。
--------------------------------------------------------------------------------
type [-all] [-type | -path] name [name ...]
没有参数的状况下,它会显示出shell如何解译name做为命令。如果有"-type",它将会显示alias、keyword、function、builtin或file。如果有"-path"的参数,它将会显示该命令的路径,找不到的话,不显示任何东西。如果有"-all"的参数,它将会显示所有可执行name的可能路径。type接受"-a"、"-t"、"-p"做为缩写。
--------------------------------------------------------------------------------
ulimit [-SHacdfmstpnuv [limit]]
ulimit提供了对shell的可获取资源控制的功能。
-a : 报告目前所有限制。
-c : 设定最大可产生的core档案。
-d : 行程资料段(process's data segment)最大值。
-f : 可被这个shell产生的最大档案。
-m : resident set size最大值。
-s : 堆叠最大值。
-t : CPU TIME最大值(以秒计算)。
-p : pipe size in 512-byte blocks的最大值。
-n : 可开启的file descriptors最大值。
-u : 单一使用者可使用的最大process数。
-v : 该shell最大虚拟记忆体可用值。
所有项目是以1024做为单位。
quickleader 2004-7-16 17:00
Re:shell programming
Linux程式设计-11.Shell Script(bash)--(14)Bash内建参数
<!-- CETagParser ~url
<a href="http://www.openchess.org/noitatsko/programming/" target=_blank>http://www.openchess.org/noitatsko/programming/<!-- CETagParser ~/url
</a> (2001-05-25 21:04:01)
PPID : 该bash的呼叫者process ID.
PWD : 目前的工作目录。
OLDPWD : 上一个工作目录。
REPLY : 当read命令没有参数时,直接设在REPLY上。
UID : User ID。
EUID : Effective User ID。
BASH : Bash的完整路径。
BASH_VERSION : Bash版本。
SHLVL : 每次有Bash执行时,数字加一。
RANDOM : 每次这个参数被用到时,就会产生一个乱数在RANDOM上。
SECONDS : 从这个Shell一开始启动後的时间。
LINENO : Script的行数。
HISTCMD : 历史记录数。
OPTARG : getopts处理的最後一个选项参数。
OPTIND : 下一个要由getopts所处理的参数号码。
HOSTTYPE : 机器种类。
OSTYPE : 作业系统名称。
IFS : Internal Field Separator。
PATH : 命令搜寻路径。
PATH="/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin:."
HOME : 目前使用者的home directory;
CDPATH : cd命令的搜寻路径。
ENV : 如果这个参数被设定,每次有shell script被执行时,将会执行它所设定的档名做为环境设定。
MAIL : 如果这个参数被设定,而且MAILPATH没有被设定,那麽有信件进来时,bash会通知使用者。
MAILCHECK : 设定多久时间检查邮件一次。
MAILPATH : 一串的邮件检查路径。
MAIL_WARNING : 如果有设定的话,邮件被读取後,将会显示讯息。
PS1 : 提示讯息设定,内定为"bash\$ "。(请详见提示讯息一节。)
PS2 : 第二提示讯息设定,内定为"> "。
PS3 : select命令所使用的提示讯息。
PS4 : 执行追踪时用的提示讯息设定,内定为"+ "。
HISTSIZE : 命令历史记录量,内定为500。
HISTFILE : 历史记录档,内定~/.bash_history。
HISTFILESIZE : 历史记录档行数最大值,内定500。
OPTERR : 如果设为1,bash会显示getopts的错误。
PROMPT_COMMAND : 如果设定的话,该值会在每次执行命令前都显示。
IGNOREEOF : 将EOF值当成输入,内定为10。
TMOUT : 如果设为大於零,该值被解译为输入等待秒数。若无输入,当成没有输入。
FCEDIT : fc命令的内定编辑器。
FIGNORE : 请详见READLINE。
INPUTRC : readline的startup file,内定~/.inputrc
notify : 如果设定了,bash立即报告被终结的背景程式。
history_control, HISTCONTROL : history使用。
command_oriented_history : 存入多行指令。
glob_dot_filenames : 如果设定了,bash将会把"."包含入档案路径中。
allow_null_glob_expansion : 如果设定了,bash允许路径明称为null string。
histchars : history使用。
nolinks : 如果设定了,执行指令时,不会跟随symbolic links。
hostname_completion_file, HOSTFILE : 包含与/etc/hosts相同格式的档名。
noclobber : 如果设定了,Bash不会覆写任何由">"、">&"及"<>"所操作的档案。
auto_resume : 请见任务控制一节。
no_exit_on_failed_exec : 如果该值存在,非互动的shell不会因为exec失败而跳出。
cdable_vars : 如果启动,而cd命令找不到目录,可切换到参数形态指定的目录下。
quickleader 2004-7-16 17:06
Re:shell programming
设置Unix启动密码
本文出自: <!-- CETagParser ~url
<a href="http://go3.163.com/~axiom999" target=_blank>http://go3.163.com/~axiom999<!-- CETagParser ~/url
</a> (2001-06-18 22:08:01)
在DOS和WINDOWS98系统中设置启动密码已经有很多方法和现成的软件可用了,但是,在UNIX系统中,有没有一种方法可以设置启动密码呢?下面我自编了一个SHELL小程序,可以实现在系统启动过程中加以密码限制,即使启动了机器,在输入密码之前,也不能使系统出现LOGIN的提示符。
这个小程序是加载在/etc/rc2文件中的,rc2文件是unix系统在启动过程中调用的一个shell文件,我们在最后加入如下内容,就可实现启动密码的限制了。程序如下:
在/etc/rc2文件中寻找下面这句话
if [ "${ BOOT}" = "yes" -a "$7" = "2" ]
then
# dspmsg $MF_RC -s $MS_RC2 $RC2_READY 'The System is Ready ! \n'
找到后
屏蔽上面这句话,之后加入下面这个程序:
# 循环开始
while true
do
clear
setcolor -b black -k lt_red
echo '\033[09;18H 系'
setcolor -b black -k lt_cyan
echo '\033[09;25H 统'
setcolor -b black -k lt_magenta
echo '\033[09;32H 启'
setcolor -b black -k hi_white
echo '\033[09;39H 动'
setcolor -b black -k yellow
echo '\033[09;46H 完'
setcolor -b black -k lt_green
echo '\033[09;53H 毕'
setcolor -b black -k white
echo '\n\n\n\n\n\n\n\n\n\n\n\n\n'
echo ' ┏━━━━━━━━━━━━━━━━━┓'
echo ' ┃ 欢 迎 您 使 用 UNIX ┃'
echo ' ┗━━━━━━━━━━━━━━━━━┛'
echo "\033[17;15H 请输入密码:[****] "
setcolor -b black -k black
echo "\033[17;42H\c"
read ch
setcolor -b black -k white
# 在上面的两个setcolor语句中,可以使键入的密码不回显
case $ch in
# 以下括号内为启动密码
2015)
setcolor -b black -k lt_green
echo " "
echo " "
echo "密码正确,请使用本系统."
setcolor -b black -k white
break
;;
*)
echo "\007"
echo "\033[20;1H"
setcolor -b black -k lt_red
echo "\007\t\t\t 密码错误!!!,请重新输入\c"
setcolor -b black -k white
read s
;;
esac
done
# 循环结束
elif [ "$7" = "2" ]
then
dspmsg $MF_RC -s $MS_RC2 $RC2_COMPLETE 'Change to state 2 has been completed.\n'
fi
如果在while循环中,每一条setcolor语句下面加如sleep 1(延迟1秒),更能获得动态
的效果!
quickleader 2004-7-16 17:07
Re:shell programming
shell实现Unix进程间信息交换的几种方法
本文出自:计算机世界2000年第32期 作者: 北京中软同和公司 何绍德 (2001-06-26 22:08:00)
本文将介绍在SCO OpenServer5.0.5系统中使用shell语言来实现进程间信息交换的几种方法:
使用命名管道实现进程间信息交换
使用kill命令和trap语句实现进程间信息交换
使用点命令“.”实现进程间信息交换
使用export语句实现父进程对子进程的信息传递
一、使用命名管道
命名管道是一种先进先出(FIFO)的数据结构,它允许两个进程通过管道联接实现信息交换。
在Unix系统中,命名管道是一种特殊类型的文件,因此可以对命名管道进行读写操作;当然,同样
也会有读写和执行等权限的限制。
通过下面的命令可以创建一个命名管道:
/etc/mknod pipe_name p
其中“pipe_name”是要创建的命名管道的名字,参数p 必须出现在命名管道名字之后。
命名管道文件被创建后,一些进程就可以不断地将信息写入命名管道文件里,而另一些进程也
可以不断地从命名管道文件中读取信息。对命名管道文件的读写操作是可以同时进行的。下面的例子
显示命名管道的工作过程。
进程A、B、C中运行的程序只是一条简单的echo命令,它们不断地把信息写入到命名管道文件
/tmp/pipe1中。与此同时,程序中的“read msg” 命令不断地从命名管道文件/tmp/pipe1中读取这些
信息,从而实现这些进程间的信息交换。
程序执行时,首先创建命名管道文件,此时程序处于等待状态,直到A、B、C进程中某一个进程往
命名管道中写入信息时,程序才继续往下执行。使用rm命令可以删除命名管道文件从而清除已设置的
命名管道。
下面是一个用于记录考勤的例子:
在主机上运行的程序/tmp/text产生命名管道/tmp/pipe1,并不断地从命名管道中读取信息送屏幕
上显示。
/tmp/text程序:
if [ ! -p /tmp/pipe1 ]
then
/etc/mknode /tmp/pipe1 p
fi
while :
do
read msg
if [ “$msg" = “" ]
then
continue
else
echo “$msg"
fi
done < /tmp/pipe1
在终端上运行的是雇员签到程序/tmp/text1。每个雇员在任何一台终端上键入自己的名字或代码,
程序/tmp/text1将把这个名字连同当时的签到时间送入命名管道。
/tmp/text1程序:
tty=‘who am I | awk ‘{ print $2}’’
while :
do
echo “Enter your name: \c" > /dev/$tty
read name
today=‘date’
echo “$name\t$today"
done > /tmp/pipe1
当雇员从终端上输入自己的姓名后,运行/tmp/text程序的主机将显示类似下面的结果:
wang Thu Jan 28 09:29:26 BTJ 1999
he Thu Jan 28 09:29:26 BTJ 1999
cheng Thu Jan 28 09:30:26 BTJ 1999
zhang Thu Jan 28 09:31:26 BTJ 1999
二、使用kill命令和trap语句
在Unix系统中,当检测到一个异常的内部状态,或者硬件及外部设备发出请求,或者执行某些指令时,
将会向系统中的进程发出信号报告事件产生。当进程捕获到这些信号后,系统便转去执行预先设定的默认
程序,完成指定的动作;这些预先设定的默认程序称之为信号的系统陷阱。
在shell中,使用trap语句为信号设置新的陷阱。当shell 捕获到一个信号时(信号11除外,因为
shell本身要利用这个信号进行内存分配),它将这个信号传递给所有当前正在执行的程序
(父程序和子程序),并分别执行父程序和子程序中已设置的信号陷阱。一旦陷阱程序执行结束,便返
回中断点,继续执行原来的程序流程。
trap语句的基本格式:
trap command_list signal_list
command_list: 由一个或多个命令(或命令组)构成的命令列表。当命令列表中含有多个命令时要
用单引号或双引号括起来,并且各命令间要用分号隔开。
signal_list:由一个或多个信号值构成的信号列表,各信号值间要用空格分开。
在一个shell程序(父程序)中重新设置信号的陷阱并不改变被这个程序所调用的子程序中同名信号
的陷阱。同样,在子程序中设置的信号陷阱也不影响父程序中同名信号的陷阱。
shell在读取trap语句时,要扫描一次命令列表,以便设置陷阱。在捕获信号后,shell再次扫描命令
列表,执行已设置好的陷阱程序(命令或命令组)。因此,如果命令列表中含有变量置换或命令置换表达
式,shell在第一次扫描命令列表时就会用当前的变量值或命令结果置换这些表达式,使得在捕获到信号而
去执行陷阱程序时,陷阱程序已经不是原来设置的陷阱程序了。为了避免这种情况发生,使用单引号而不是
使用双引号把trap语句中含有变量置换或命令置换表达式的命令列表括起来;因为单引号可以消除所有字符
的特殊含义,这样避免了shell在第一次扫描时执行任何置换或替代操作,直到命令列表被执行时才进行置
换或替代。
向一个程序或进程传递信号方法很多,比如在程序执行时按下Ctrl+c键或Del键,将向程序传递一个
SIGINT信号,执行该信号的系统陷阱将终止程序执行。使用kill命令传递信号是shell语言编程中最为常用
的方法。
kill命令的基本格式是:
kill [ - signal ] PID
通常kill命令用来终止一个进程。但如果使用了带有短划线“-”的信号作为参数时,kill命令就发送
该信号给PID指示的一个或多个进程,而不是终止进程。当trap语句捕获到这个信号后便执行设定的信号陷阱
程序,实现进程间的相互通讯。
下面的例子显示了程序master和slave1、slave2间如何利用信号机制实现相互通讯的。首先在后台运行
程序slave1和slave2,然后运行程序master。在文件/tmp/pro_list中记录了这三个程序的进程号。
程序slave1首先设置信号15的陷阱,然后把自己的当前进程写入文件/tmp/pro_list;在获得master进程
号后,进入循环状态。当接收到master发出的信号15时,执行陷阱程序,显示相关信息后,向master发出信
号15。
程序slave2执行情况与slave1相似。
程序master也是首先设置信号15的陷阱,然后把自己的当前进程写入文件/tmp/pro_list。在取得所有
slave程序进程号后,向这些slave程序发出信号15,然后进入循环等待。当接收到slave1或slave2发出的信
号15时,执行陷阱程序,显示相关信息,杀死所有slave进程,清空文件/tmp/pro_list,然后退出。
程序/tmp/slave1:
slave() {
echo “slave1 has received sighal from master"
echo “Request master to kill slave1 process"
kill -15 $master_pid
}
trap slave 15
echo “slave1_pid $$" >> /tmp/pro_list
sleep 1
while :
do
master_pid=‘awk ’$1 ~/master/
{ print $2}‘/tmp/pro_list’
if [ “$master_pid" != “" ]
then break
fi
done
while :
do
sleep 1
done
程序/tmp/slave2:
slave() {
echo “slave2 has received sighal from master"
echo “Request master to kill slave2 process"
kill -15 $master_pid
}
trap slave 15
echo “slave2_pid $$" >> /tmp/pro_list
sleep 1
while :
do
master_pid=‘awk ’$1 ~/master/
{ print $2}‘/tmp/pro_list’
if [ “$master_pid" != “" ]
then break
fi
done
while :
do
sleep 1
done
程序/tmp/master:
kill_slave() {
echo “Master has received signals
from slave processes"
echo “End all slave processes"
kill -9 $slave_list
>/tmp/pro_list
exit 0
}
trap kill_slave 15
echo “master_pid $$" >> /tmp/pro_list
sleep 1
slave_list=‘awk ’$1 ~/slave/
{ print $2}‘/tmp/pro_list’
echo “Current slave processes are:"
echo “$slave_list"
kill -15 $slave_list
while :
do
sleep 1
done
执行程序:
$ cd /tmp
$ ./slave1&
15638
$ ./slave2&
16831
$ ./master
Current slave processes are:
15638
16831
slave1 has received signal 15 from master
Request master to kill slave1 process
slave2 has received signal 15 from master
Request master to kill slave2 process
Master has received signals from slave processes
End all slave processes
15638 Killed
16831 Killed
$
三、使用点命令“.”
“.”点命令是shell的一个内部命令,它从指定的shell 文件中读入所有命令语句并在当前进程
中执行。 因此当多个shell进程(父子进程或无关进程均可)共享一组变量值时,就可以将这些变量
赋值语句定义到一个shell文件里,并在需要这些变量值的程序中使用点语句来引用这个shell文件,
从而实现变量值共享(对这些变量值的修改仅涉及到这个shell文件)。但要注意的是,这个shell文
件不能包括含有位置参数的语句,即不能接受$1、$2等命令行参数。
下面是一个在超市中发布每日商品价格的示范程序片段。发布每日商品价格统一由程序/tmp/jiage
来执行,它为每种商品价格赋值,并把相应的赋值语句写入文件/tmp/jiagebiao中。在各终端上运行的
收款程序/tmp/shoukuan将读入文件 /tmp/jiagebiao中所有赋值语句并在当前进程中执行,从而获取在
程序/tmp/jiage中设定的价格。
价格设定程序/tmp/jiage:
echo “Enter the price of chicken,
duck and fish: \c"
read chicken duck fish
exec 3>/tmp/jiagebiao
echo “chicken_price=$chicken" >&3
echo “duck_price=$duck" >&3
echo “fish_price=$fish" >&3
执行/tmp/jiage程序后,文件/tmp/jiagebiao中将有如下内容:
chicken_price=5.4
duck_price=2.5
fish_price=4.2
收款程序/tmp/shoukuan:
. /tmp/jiagebiao
count=0
while :
do
echo “Enter the trade name and
quantities or input q to sum: \c"
read trade$count quantity$count
eval a=\$trade$count
if [ “$a" = “q" ]
then if [ $count -gt 0 ]
then
count=‘expr $count - 1’
fi
break
fi
count=‘expr $count + 1 ’
done
echo “\n‘date’"
echo “trade name\tquantity\tsum"
while [ “$count" -ge 0 ]
do
eval trade=“\${ trade$count}"
eval trade_price=“${ trade}_price"
eval danjia=\${ $trade_price}
eval quantity=“\${ quantity$count}"
sum=‘echo “scale=2; $danjia
*$quantity"|bc’
echo “$trade\t\t$quantity\t\t$sum"
count=‘expr $count - 1 ’
done
在终端上执行程序/tmp/shoukuan将有如下显示:
Enter the trade name and quantities
or input q to sum: chicken 2
Enter the trade name and quantities
or input q to sum: fish 3
Enter the trade name and quantities
or input q to sum: duck 4
Enter the trade name and quantities
or input q to sum: q
Thu Jan 28 09:29:29 BJT 1999:
duck 4 10
fish 3 12.6
chicken 2 10.8
四、使用export语句
通常shell变量是局部变量,无论是通过赋值操作还是通过命令赋值,其变量值只在当前进程中
有效。但是经过export语句说明的shell变量就成为一个全局性变量,其变量名和变量值可以传递给
子进程及其后代进程。在子进程中可以修改这个变量的值,但并不影响这个变量在父进程中的取值。
下面的例子中,父进程(/tmp/text)将赋值后的变量 pro_name传递给子进程(/tmp/text_child),
在子进程中对变量pro_name所赋的新值并不影响父进程中该变量的值。
/tmp/text程序:
pro_name=“PARENT"
echo “The variable pro_name is
$pro_name in parent process"
export pro_name
/tmp/text_child
echo “The variable pro_name is
$pro_name after retund to parent process"
/tmp/text_child程序:
echo“The variable pro_name ($pro_name) is
transmited to child process"
pro_name=“CHILD"
echo “To change the variable pro_name to
$pro_name in child process"
执行程序/tmp/text:
$ /tmp/text
The variable pro_name is PARENT
in parent process
The variable pro_name (PARENT)
is transmited to child process
To change the variable pro_name to CHILD
in child process
The variable pro_name is PARENT
after retund to parent process
$
quickleader 2004-7-16 17:08
Re:shell programming
介绍B-SHELL的一些运用方法
本文出自:http://www.fanqiang.com 作者: truename [luoli1974@163.com] (2001-08-22 17:30:12)
前言:
这里只介绍B-SHELL的一些运用方法,不对B-SHELL的基本知识进行说明(与其他的语言有很多的共性,果你懂一种语言的话,很快就能上手),如你是对B-SHELL不是很了解的话,而且又想学的话,建议你去查阅相关的资料(网上有很多关于这方面的东东;当然也可买些书;如果你是一个借别人的书才能阅读的人,那就去借吧!我就是这样的人之一。)。我的能力有限,若有不足或错误,请多多指教,小弟将感激不尽!所有的介绍适合于内核2.2.13的及以上的liunx环境。
B-SHELL是一个便捷的开发工具,在紧急情况下要实现产品的某一功能,而用C语言不能很快完成,则可选择B-SHLL实现,日后再用C语言完成;在产品里对于那些不常运行的程序可用B-SHELL替代,这样可以避免因对C语言使用不当而带来的不良后果;对于一些处理量不大的程序可用B-SHELL实现。
讨论:
#!/bin/sh à B-SHELL的解释器标志
ALL=$@
#{
B-SHELL中带”$”的变量的说明:$0à SHELL命令本身
$nà 位置参数n(n != 0)
$@à 所有的输入变量
$$à 当前进程号
$!à 最近后台进程的PID值
$?à 最近命令执行状态的返回值
$#à 参数的个数
}#
declare -x TIME=0
#{
变量声明的说明:
declare 声明全局变量;如果在函数内声明,则只在函数内有效(局部变量);-x表明变量值可以传递给后继命令(从函数传值给后继命令);-i表明变量作为整型处理;-r表明变量为只度;用“+”代替“-”,原有变量的声明屏蔽,恢复为无定义状态。由第一次赋值决定其参数在脚本中的性质,如果首次是字符,以后都当字符处理,其它等同。
local声明局部变量;local 变量名 [ = “值”];一般在函数内部运用。
直接定义变量,不用declare 和local指明。由第一次赋值决定其参数在脚本中的性质,如果首次是字符,以后都当字符处理,其它等同。也可在定义确定。
}#
declare -x NUMBEROFFILE=0
#{
关于脚本函数说明:
定义方式:function 函数名() 或 函数名()
{
函数体(作你想要作的事)
}
调用方式:函数名 参数列
在脚本里函数的调用就象调用命令一样使用。à 后面将会提到
}#
function hel_ver() à 显示帮助信息或版本号
{
if [ "$1" = "-h" ] ;then
echo "fstrf -v :show version of shell script."
echo "Usages : fstrf -h||-v "
echo " fstrf ARGUMENTS DIRECTORY STRING || fstrf ARGUMENTS STRING "
echo " For more informations run man fstrf."
exit
fi
if [ "$1" = "-v" ] || [ "$1" = "version" ];then
echo "fstrf version 1.0.1 2001/07/05."
exit
fi
}
function find_offer() à 在给定的目录下查找是否有包含指定字串的文件,并显示其路径
{
for file in `ls "$1"` à for var in command do ………done 的一个典型运用;对$1目录下的目录或文件进行处理
do
if [ -d "$1"/$file ];then à 判断$file是否为目录
continue
else
string=`grep "$2" "$1"/$file ` à 查找字串
if [ -n "$string" ];then à 判断字串为非空
echo $string > /str
str=`awk '{ print $1 }' /str` à 取得str 的第一域值
rm /str
if [ "$str" != "Binary" ];then à 剔除二进制文件
NUMBEROFFILE=`expr $NUMBEROFFILE + 1 ` à 相当于C语言的NUMBEROFFILE +=1;可用
let ‘ NUMBEROFFILE=NUMBEROFFILE + 1‘替换
TIME=`expr $TIME + 1`
echo "$1/$file" à 显示匹配文件
fi
fi
fi
done
}
#else
function find_curr() à 在当前目录下查找是否有包含指定字串的文件,并显示其路径(相对路径)实现机制与find_offer相同
{
# if [ "$#" -eq "1" ];then à
for file in `ls ./` 如果只输入一个参数,则查找当前工作目录下的文件
do
if [ -d "$file" ];then
continue
else
string=`grep "$1" $file`
if [ -n "$string" ];then
echo $string > /str
str=`awk '{ print $1 }' /str`
rm /str
if [ "$str" != "Binary" ];then
NUMBEROFFILE=`expr $NUMBEROFFILE + 1 `
TIME=`expr $TIME + 1`
echo "./$file"
fi
fi
fi
done
}
function print_num() à 显示查找的文件数 (在查多级目录时未能实现,如果你知道,告诉我,我会很高兴的!)
{
if [ "$NUMBEROFFILE" -gt "0" ] ;then
# echo ""
if [ "$#" -eq "1" ];then
#{
关于彩色显示的说明:
不同的linux系统,运行的命令的方式都不一样。在LINUX/BSD系统中:echo -e “\033[40;32m”;在V系统中:echo “\033[40;32m”。本例中采用前一种方式。40位为背景色,取值40��47之间;32位为前景色,取值30��37之间;\033是固定用法。彩色显示要成队匹配,如脚本所示。通常后一个色彩控制为
echo -e "\033[40;37m" (意思是恢复正常色)。彩色显示控制通常是成对出现,例如,
`echo -e "\033[40;33m"`"$2"`echo -e "\033[40;37m"`
echo -e "\033[40;37m"à 恢复正常显示(黑背景,白前景)。利用彩色显示控可以作出漂亮的liunx菜单(当然不能与Xwindows和WINDOWS相比)。
}#
echo "Finded `echo -e "\033[40;32m"`$NUMBEROFFILE`echo -e "\033[40;37m"` file(s) which have the string `echo -e "\033[40;33m"`"$1"`echo -e "\033[40;37m"` ."
else
echo "Finded `echo -e "\033[40;32m"`$NUMBEROFFILE`echo -e "\033[40;37m"` file(s) which have the string `echo -e "\033[40;33m"`"$2"`echo -e "\033[40;37m"`. "
fi
else
if [ -z "$2" ];then
echo "Finded `echo -e "\033[40;32m"`no `echo -e "\033[40;37m"`file under current directory."
else
echo "Finded `echo -e "\033[40;32m"`no `echo -e "\033[40;37m"`file under directory "$1"."
fi
fi
}
function fdir() à 从给定的目录开始查找当前目录及其子目录的包含的目录,并存入/tmp/dtmp文件。
{
>/tmp/dtmp
#cd /
echo "$1" >/tmp/dtmp
tmp=`echo $1 | grep "\/proc"`à 不查找/proc目录下的目录
if [ ! -z $tmp ];then
# echo "/proc"
exit
fi
i=`expr $i + 1 ` à 记录找到的目录数目,每向/tmp/dtmp文件加一目录记录时此值加一(以下同样)
###first grade
cd $1 à 进入脚本的工作目录(不会改变控制台的工作目录)
for loop in `ls ./`
do
# echo $loop
if [ -d $loop ];then à 判断$loop是否为目录(以下同样)
tmp=`echo $loop | grep "proc"`
if [ ! -z $tmp ];then
continue
fi
i=`expr $i + 1 `
echo "`pwd`/$loop" >>/tmp/dtmp à 连同目录的绝对路径加入/tmp/dtmp文件(以下同样)
###second grade
cd $loop à 进入脚本二级工作目录
for loop1 in `ls ./`
do
# echo $loop1
if [ -d $loop1 ];then
tmp=`echo $loop1 | grep "proc"`
if [ ! -z $tmp ];then
continue
fi
i=`expr $i + 1 `
echo "`pwd`/$loop1" >>/tmp/dtmp
###third grade
cd $loop1à 进入脚本三级工作目录
for loop1 in `ls ./`
do
# echo $loop1
if [ -d $loop1 ];then
i=`expr $i + 1 `
echo "`pwd`/$loop1" >>/tmp/dtmp
…………
………
………
………
…………
else
continue
fi
done
cd .. à 退出脚本三级工作目录,进入脚本二级工作目录
else
continue
fi
done
cd ..à 退出脚本二级工作目录,进入脚本一级工作目录
else
continue
fi
done
}
#{
test的用法说明:在脚本里,用一对[ ]表示test,如[ "$#" -eq "0" ]。注意:参数与[]之间一定要有空格(最好是所有的参数之间都要有空格)。如果不了解test参数的用法,运行man test,只要你学过英语你一定能看懂;实在没有办法,那就上网去查吧!
}#
##main shell
if [ "$#" -eq "0" ];then
echo "`echo -e "\033[40;33m"`run fstrf -h or man fstrf `echo -e "\033[40;37m"`to get more help informations."
echo "`echo -e "\033[40;36m"`list current directory:`echo -e "\033[40;37m"`"
ls ./
echo "`echo -e "\033[40;36m"`no string input!!!`echo -e "\033[40;37m"`"
exit
fi
hel_ver $ALL à 调用hel_ver函数
if [ "$1" = "-up" ];then à 查找指定当前目录内及字目录内的文件
if [ "$#" -eq "3" ];then
fdir $2 $3 2>/dev/null 1>&2 à 将所有的错误输出均输向/dev/null(不在屏幕上回显,以下一样)
#{
while read var do .. done的重定向说明:
有两种方式: 1. while read var do .. done < 重定向文件的路径及文件名
while read var
do
..
done < 重定向文件的路径及文件名
2. dd if=重定向文件的路径及文件名 bs=512 2>/dev/null | while read var do .. done
dd if=重定向文件的路径及文件名 bs=512 2>/dev/null | \
while read var
do
..
done
}#
#{
关于函数调用的说明:
在脚本中函数的调用类似与LINUX命令的调用,只是变量要用“”括起来。函数内部的$n只相对与函数的参数位置,如find_offer "$DIR" "$3",find_offer内的$1对应于"$DIR",$2对应于"$3",与SHELL 主程序的$n无对应关系,既函数的$1不一定要等于SHELL主程序的$1。
}#
dd if=/tmp/dtmp bs=512 2>/dev/null | \
while read DIR
do
find_offer "$DIR" "$3"
done
# print_num "$2" "$3"
fi
if [ "$#" -eq "2" ];then à 查找指定当前工作目录内及字其目录内的文件
fdir ./ 2>/dev/null 1>&2
dd if=/tmp/dtmp bs=512 2>/dev/null | \
while read DIR
do
find_offer "$DIR" "$2"
done
# print_num "$2"
fi
fi
if [ "$1" = "-cu" ];then à 查找当前目录或指定当前目录内的文件
if [ "$#" -eq "2" ];then à 查找当前目录匹配的文件
find_curr "$2"
print_num "$2" à 显示匹配的文件数
fi
if [ "$#" -eq "3" ];then à 查找指定当前目录内的文件
find_offer "$2" "$3"
print_num "$3" à 显示匹配的文件数
fi
fi
if [ -e /tmp/dtmp ];then à 文件存在则删除
rm /tmp/dtmp
fi
quickleader 2004-7-16 17:09
Re:shell programming
shell编程例子 -- 一个.cshrc例子
本文出自: 作者: (2001-10-01 09:00:00)
*****************************************************************
# * *
# * *
# *****************************************************************
#
# HISTORY
#
# @(#)$RCSfile: .cshrc,v $ $Revision: 4.1.3.3 $ (DEC) $Date: 1992/05/11 09:13:09
$
#
setenv MAIL /usr/spool/mail/$USER
#******************************************************************************
#******************************************************************************
#
# add by zzy 2000.08.06
#
#******************************************************************************
#******************************************************************************
# set pics environment
#******************************************************************************
#source /etc/pics.d/picsenv.csh
#******************************************************************************
# set innovator environment
#******************************************************************************
#source /usr/innovator/inoenv.csh
#******************************************************************************
# set PCFC application environment
#******************************************************************************
source ${ HOME}/app_login
#******************************************************************************
# change path to home path
#******************************************************************************
cd ${ HOME}
#******************************************************************************
app_login:
==========
#******************************************************************************
#* module: app_login
#* description: app login
#* This script must be called in the login file
#* with the command 'source app_login'
#* author: zzy
#* version: 31.08.1998
#******************************************************************************
#******************************************************************************
# entry
#******************************************************************************
#******************************************************************************
# environment
#******************************************************************************
set say = "echo"
set mode = ""
set node = "`uname -n`"
set user = "`logname`"
#******************************************************************************
# this path and this script
#******************************************************************************
set this_path1 = "`dirname ${ HOME}/x`"
set this_script1 = "app_login"
if ( ! -f ${ this_path1}/${ this_script1} ) then
$say 'this script must be in the directory $HOME'
goto exit
endif
#******************************************************************************
# start message
#******************************************************************************
$say " %$this_script1, `date '+%H:%M:%S'` start executing on $node"
#******************************************************************************
# set project and channel prefix for all user
#******************************************************************************
if ( "$user" == "root" ) then
setenv PROJ pcfc
setenv CPRE ""
endif
if ( "$user" == "pcfc" ) then
setenv PROJ pcfc
setenv CPRE ""
endif
if ( "$user" == "picsadm" ) then
setenv PROJ baoshan
setenv CPRE ""
endif
if ( "$user" == "picsvis" ) then
setenv PROJ baoshan
setenv CPRE ""
endif
if ( "$user" == "" ) then
setenv PROJ pcfc
setenv CPRE ""
endif
#******************************************************************************
# set project directory
#******************************************************************************
setenv PROJ_DIR /home/$PROJ
#******************************************************************************
# call project application login
#******************************************************************************
if ( -f "${ this_path1}/${ this_script1}_$PROJ" ) then
$say " %$this_script1, call project application login"
source ${ this_path1}/${ this_script1}_$PROJ
endif
#******************************************************************************
# end message
#******************************************************************************
#$say " %$this_script1, `date '+%H:%M:%S'` finished"
#******************************************************************************
# exit
#******************************************************************************
exit:
unset this_path1
unset this_script1
exit
#******************************************************************************
app_login_pcfc
==============
#******************************************************************************
#* module: application_login_$PROJ
#* description: application login for a project
#* This script must be called in the login file app_login
#* with the command 'source app_login_$PROJ'
#* author: Zhou zeyan
#*
#* version: 8.1.2000
#******************************************************************************
#******************************************************************************
# entry
#******************************************************************************
#******************************************************************************
# environment
#******************************************************************************
set say = "echo"
set mode = ""
set node = "`uname -n`"
set user = "`logname`"
#******************************************************************************
# this path and this script
#******************************************************************************
set this_path2 = "`dirname ${ HOME}/x`"
set this_script2 = "app_login_$PROJ"
#******************************************************************************
# start message
#******************************************************************************
$say " %$this_script2, `date '+%H:%M:%S'` start executing on $node"
#******************************************************************************
# history
#******************************************************************************
set history=40
alias h history
#******************************************************************************
# aliases
#******************************************************************************
alias sql sqlplus pcfcadm/pcfcadm
#******************************************************************************
# set environment for components
#******************************************************************************
set cmp = glb
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = utl
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = com
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = log
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = tel
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = mva
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = mtr
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = mm
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = de
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = se
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = comtcp
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
set cmp = sdd
if ( -r "${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init" ) then
source ${ PROJ_DIR}/${ cmp}/etc/${ cmp}_init
endif
unset cmp
#******************************************************************************
# set environment for project
#******************************************************************************
if ( -r "${ PROJ_DIR}/login/login" ) then
source ${ PROJ_DIR}/login/login
endif
#******************************************************************************
# end message
#******************************************************************************
#$say " %$this_script2, `date '+%H:%M:%S'` finished"
#******************************************************************************
# unset
#******************************************************************************
exit:
unset this_path2
unset this_script2
exit
#******************************************************************************
login
========
#******************************************************************************
#* module: login
#* description: project login definitions
#* author: Zhou zeyan
#* version: 31.08.2000
#******************************************************************************
#******************************************************************************
# entry
#******************************************************************************
#******************************************************************************
# environment
#******************************************************************************
set say = echo
set mode = ""
set node = "`uname -n`"
set user = "`logname`"
#******************************************************************************
# pathes
#******************************************************************************
set path_project_login = "${ PROJ_DIR}/login"
set path_project_com = "${ path_project_login}/com"
#******************************************************************************
# definitions make
#******************************************************************************
if ( -r "${ path_project_com}/def_make" ) then
source ${ path_project_com}/def_make
endif
#******************************************************************************
# definitions path
#******************************************************************************
if ( -r "${ path_project_com}/def_path" ) then
source ${ path_project_com}/def_path
endif
#******************************************************************************
# definitions unix commands
#******************************************************************************
if ( -r "${ path_project_com}/def_unix" ) then
source ${ path_project_com}/def_unix
endif
#******************************************************************************
# definitions user commands
#******************************************************************************
if ( -r "${ path_project_com