文档库 最新最全的文档下载
当前位置:文档库 › Shell十三问-ChinaUnix精华贴整理

Shell十三问-ChinaUnix精华贴整理

Shell十三问-ChinaUnix精华贴整理
Shell十三问-ChinaUnix精华贴整理

转自ChinaUnix

1) 为何叫做shell ?

在介绍shell 是甚么东西之前,不妨让我们重新查看用户与计算机系统的关系:

图(FIXME)

我们知道计算机的运作不能离开硬件,但用户却不能直接对硬件作驱动,

硬件的驱动只能通过一个称为"操作系统(Operating System)"的软件来控管,

事实上,我们每天所谈的linux ,严格来说只是一个操作系统,我们称之为"核心(kernel)"。

然而,从用户的角度来说,用户也没办法直接操作kernel ,

而是通过kernel 的"外壳"程序,也就是所谓的shell ,来与kernel 沟通。

这也正是kernel 跟shell 的形像命名关系。如图:

图(FIXME)

从技术角度来说,shell 是一个用户与系统的交互界面(interface),

主要是让用户通过命令行(command line)来使用系统以完成工作。

因此,shell 的最简单的定义就是---命令解释器(Command Interpreter):

* 将用户的命令翻译给核心处理,

* 同时,将核心处理结果翻译给用户。

每次当我们完成系统登录(log in),我们就取得一个交互模式的shell ,也称为login shell 或primary shell。

若从进程(process)角度来说,我们在shell 所下达的命令,均是shell 所产生的子进程。这现像,我们暂可称之为fork 。

如果是执行脚本(shell script)的话,脚本中的命令则是由另外一个非交互模式的子shell (sub shell)来执行的。

也就是primary shell 产生sub shell 的进程,sub shell 再产生script 中所有命令的进程。

(关于进程,我们日后有机会再补充。)

这里,我们必须知道:kernel 与shell 是不同的两套软件,而且都是可以被替换的:

* 不同的操作系统使用不同的kernel ,

* 而在同一个kernel 之上,也可使用不同的shell 。

在linux 的缺省系统中,通常都可以找到好几种不同的shell ,且通常会被列与如下文件里:

/etc/shells

不同的shell 有著不同的功能,且也彼此各异、或说"大同小异"。

常见的shell 主要分为两大主流:

sh:

burne shell (sh)

burne again shell (bash)

csh:

c shell (csh)

tc shell (tcsh)

korn shell (ksh)

(FIXME)

大部份的Linux 系统的缺省shell 都是bash ,其原因大致如下两点:

* 自由软件

* 功能强大

bash 是gnu project 最成功的产品之一,自推出以来深受广大Unix 用户喜爱,

且也逐渐成为不少组织的系统标准。

2) shell prompt(PS1) 与Carriage Return(CR) 的关系?

当你成功登录进一个文字界面之后,大部份情形下,

你会在荧幕上看到一个不断闪烁的方块或下划线(视不同版本而别),

我们称之为*光标*(cursor)。

光标的作用就是告诉你接下来你从键盘输入的按键所插入的位置,

且每输如一键光标便向右边移动一个格子,若连续输入太多的话,则自动接在下一行输入。

假如你刚完成登录还没输入任何按键之前,你所看到的光标所在位置的同一行的左边部份,

我们称之为*提示符号*(prompt)。

提示符号的格式或因不同系统版本而各有不同,在Linux 上,只需留意最接近光标的一个可见的提示符号,通常是如下两者之一:

$:给最终用户帐号使用

#:给root (管理员)帐号使用

事实上,shell prompt 的意思很简单:

* 是shell 告诉用户:您现在可以输入命令行了。

我们可以说,用户只有在得到shell prompt 才能打命令行,

而cursor 是指示键盘在命令行所输入的位置,用户每输入一个键,cursor 就往后移动一格,

直到碰到命令行读进CR(Carriage Return,由Enter 键产生)字符为止。

CR 的意思也很简单:

* 是用户告诉shell:老兄你可以执行我的命令行了。

严格来说:

* 所谓的命令行,就是在shell prompt 与CR 字符之间所输入的文字。

(思考:为何我们这里坚持使用CR 字符而不说Enter 键呢?答案在后面的学习中揭晓。)

不同的命令可接受的命令行格式或有不同,一般情况下,一个标准的命令行格式为如下所列:

command-name options argum ent

若从技术细节来看,shell 会依据IFS(Internal Field Seperator) 将comm and line 所输入的文字给拆解为"字段"(word)。

然后再针对特殊字符(meta)先作处理,最后再重组整行command line 。

(注意:请务必理解上两句话的意思,我们日后的学习中会常回到这里思考。)

其中的IFS 是shell 缺省使用的字段分隔符号,可以由一个及多个如下按键组成:

* 空白键(White Space)

* 表格键(Tab)

* 回车键(Enter)

系统可接受的命令名称(command-name)可以从如下途迳获得:

* 明确路径所指定的外部命令

* 命令别名(alias)

* 自定功能(function)

* shell 内置命令(built-in)

* $PATH 之下的外部命令

每一个命令行均必需含用命令名称,这是不能缺少的。

3) 别人echo、你也echo ,是问echo 知多少?

承接上一章所介绍的 command line ,这里我们用echo 这个命令加以进一步说明。

温习---标准的command line 包含三个部件:

* command_name option argument

echo 是一个非常简单、直接的Linux 命令:

* 将argument 送出至标准输出(STDOUT),通常就是在监视器(monitor)上输出。

(注:stdout 我们日后有机会再解说,或可先参考如下讨论:

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=191375 )

为了更好理解,不如先让我们先跑一下echo 命令好了:

CODE:

$ echo

$

你会发现只有一个空白行,然后又回到shell prompt 上了。

这是因为echo 在缺省上,在显示完argument 之后,还会送出一个换行符号(new-line charactor)。

但是上面的comm and 并没任何的argument ,那结果就只剩一个换行符号了...

若你要取消这个换行符号,可利用echo 的-n option :

CODE:

$ echo -n

$

不妨让我们回到command line 的概念上来讨论上例的echo 命令好了:

* command line 只有command_name(echo) 及option(-n),并没有任何argument 。

要想看看echo 的argument ,那还不简单!接下来,你可试试如下的输入:

CODE:

$ echo first line

first line

$ echo -n first line

first line $

於上两个echo 命令中,你会发现argument 的部份显示在你的荧幕,而换行符号则视-n option 的有无而别。很明显的,第二个echo 由於换行符号被取消了,接下来的shell prompt 就接在输出结果同一行了... ^_^

事实上,echo 除了-n options 之外,常用选项还有:

-e :启用反斜杠控制字符的转换(参考下表)

-E:关闭反斜杠控制字符的转换(缺省如此)

-n :取消行末之换行符号(与-e 选项下的\c 字符同意)

关於echo 命令所支持的反斜杠控制字符如下表:

\a:ALERT / BELL (从系统喇叭送出铃声)

\b:BACKSPACE ,也就是向左删除键

\c:取消行末之换行符号

\E:ESCAPE,跳脱键

\f:FORMFEED,换页字符

\n:NEWLINE,换行字符

\r:RETURN,回车键

\t:TAB,表格跳位键

\v:VERTICAL TAB,纵向表格跳位键

\n:ASCII 八进制编码(以x 开首为十六进制)

\\:反斜杠本身

(表格数据来自O'Reilly 出版社之Learning the Bash Shell, 2nd Ed.)

或许,我们可以通过实例来了解echo 的选项及控制字符:

例一:

CODE:

$ echo -e "a\tb\tc\nd\te\tf"

a b c

d e f

上例运用\t 来区隔abc 还有def ,及用\n 将def 换至下一行。

例二:

CODE:

$ echo -e "\141\011\142\011\143\012\144\011\145\011\146"

与例一的结果一样,只是使用ASCII 八进制编码。

例三:

CODE:

$ echo -e "\x61\x09\x62\x09\x63\x0a\x64\x09\x65\x09\x66"

a b c

d e f

与例二差不多,只是这次换用ASCII 十六进制编码。

例四:

CODE:

$ echo -ne "a\tb\tc\nd\te\bf\a"

a b c

d f $

因为 e 字母后面是删除键(\b),因此输出结果就没有 e 了。

在结束时听到一声铃向,那是\a 的杰作!

由於同时使用了-n 选项,因此shell prompt 紧接在第二行之后。

若你不用-n 的话,那你在\a 后再加个\c ,也是同样的效果。

事实上,在日后的shell 操作及shell script 设计上,echo 命令是最常被使用的命令之一。

比方说,用echo 来检查变量值:

CODE:

$ A=B

$ echo $A

B

$ echo $?

(注:关於变量概念,我们留到下两章才跟大家说明。)

好了,更多的关於command line 的格式,以及echo 命令的选项,

就请您自行多加练习、运用了...

4) " "(双引号) 与' '(单引号)差在哪?

还是回到我们的command line 来吧...

经过前面两章的学习,应该很清楚当你在shell prompt 后面敲打键盘、直到按下Enter 的时候,

你输入的文字就是command line 了,然后shell 才会以行程的方式执行你所交给它的命令。

但是,你又可知道:你在command line 输入的每一个文字,对shell 来说,是有类型之分的呢?简单而言(我不敢说这是精确的定义,注一),command line 的每一个charactor ,分为如下两种:* literal:也就是普通纯文本,对shell 来说没特殊功能。

* m eta:对shell 来说,具有特定功能的特殊保留字符。

(注一:关于bash shell 在处理command line 时的顺序说明,

请参考O'Reilly 出版社之Learning the Bash Shell, 2nd Edition,第177 - 180 页的说明,

尤其是178 页的流程图Figure 7-1 ... )

Literal 没甚么好谈的,凡举abcd、123456 这些"文字"都是literal ... (easy?)

但m eta 却常使我们困惑..... (confused?)

事实上,前两章我们在command line 中已碰到两个机乎每次都会碰到的meta :

IFS 是用来拆解command line 的每一个词(word)用的,因为shell command line 是按词来处理的。而CR 则是用来结束command line 用的,这也是为何我们敲 命令就会跑的原因。

除了IFS 与CR ,常用的meta 还有:

= :设置变量。

$ :作变量或运算替换(请不要与shell prompt 搞混了)。

> :重定向stdout。

< :重定向stdin。

|:管道。

& :重定向file descriptor ,或将命令置于后台执行。

( ):将其内的命令置于nested subshell 执行,或用于运算或命令替换。

{ }:将其内的命令置于non-named function 中执行,或用在变量替换的界定范围。

; :在前一个命令结束时,而忽略其返回值,继续执行下一个命令。

&& :在前一个命令结束时,若返回值为true,继续执行下一个命令。

|| :在前一个命令结束时,若返回值为false,继续执行下一个命令。

!:执行history 列表中的命令

....

假如我们需要在command line 中将这些保留字符的功能关闭的话,就需要quoting 处理了。

在bash 中,常用的quoting 有如下三种方法:

* hard quote:' ' (单引号),凡在hard quote 中的所有m eta 均被关闭。

* soft quote:" " (双引号),在soft quoe 中大部份meta 都会被关闭,但某些则保留(如$ )。(注二) * escape :\ (反斜杠),只有紧接在escape (跳脱字符)之后的单一meta 才被关闭。

( 注二:在soft quote 中被豁免的具体meta 清单,我不完全知道,

有待大家补充,或通过实作来发现及理解。)

下面的例子将有助於我们对quoting 的了解:

CODE:

$ A=B C # 空格键未被关掉,作为IFS 处理。

$ C: command not found.

$ echo $A

$ A="B C" # 空格键已被关掉,仅作为空格键处理。

$ echo $A

B C

在第一次设置 A 变量时,由於空格键没被关闭,command line 将被解读为:

* A=B 然后碰到,再执行C 命令

在第二次设置 A 变量时,由於空格键被置于soft quote 中,因此被关闭,不再作为IFS :

* A=BC

事实上,空格键无论在soft quote 还是在hard quote 中,均会被关闭。Enter 键亦然:

CODE:

$ A='B

> C

> '

$ echo "$A"

B

C

在上例中,由於 被置於hard quote 当中,因此不再作为CR 字符来处理。

这里的 单纯只是一个断行符号(new-line)而已,由於command line 并没得到CR 字符,

因此进入第二个shell prompt (PS2,以> 符号表示),command line 并不会结束,

直到第三行,我们输入的并不在 hard quote 里面,因此并没被关闭,

此时,command line 碰到CR 字符,於是结束、交给shell 来处理。

CODE:

$ A="B

> C

> "

$ echo $A

B C

然而,由於echo $A 时的变量没至於soft quote 中,因此当变量替换完成后并作命令行重组时, 会被解释为IFS ,而不是解释为New Line 字符。

同样的,用escape 亦可关闭CR 字符:

CODE:

$ A=B\

> C\

>

$ echo $A

BC

上例中,第一个 跟第二个均被escape 字符关闭了,因此也不作为CR 来处理,

但第三个 由於没被跳脱,因此作为CR 结束command line 。

但由於 键本身在shell meta 中的特殊性,在\ 跳脱后面,仅仅取消其CR 功能,而不会保留其IFS 功能。

您或许发现光是一个 键所产生的字符就有可能是如下这些可能:

CR

IFS

NL(New Line)

FF(Form Feed)

NULL

...

至於甚么时候会解释为甚么字符,这个我就没去深挖了,或是留给读者诸君自行慢慢摸索了... ^_^

至於soft quote 跟hard quote 的不同,主要是对於某些meta 的关闭与否,以$ 来作说明:

CODE:

$ A=B\ C

$ echo "$A"

B C

$ echo '$A'

$A

在第一个echo 命令行中,$ 被置于soft quote 中,将不被关闭,因此继续处理变量替换,

因此echo 将 A 的变量值输出到屏幕,也就得到 "B C" 的结果。

在第二个echo 命令行中,$ 被置于hard quote 中,则被关闭,因此$ 只是一个$ 符号,

并不会用来作变量替换处理,因此结果是$ 符号后面接一个 A 字母:$A 。

--------------------------------------

练习与思考:如下结果为何不同?

CODE:

$ A=B\ C

$ echo '"$A"' # 最外面的是单引号

"$A"

$ echo "'$A'" # 最外面的是双引号

'B C'

(提示:单引号及双引号,在quoting 中均被关闭了。)

在CU 的shell 版里,我发现有很多初学者的问题,都与quoting 理解的有关。

比方说,若我们在awk 或sed 的命令参数中调用之前设置的一些变量时,常会问及为何不能的问题。

要解决这些问题,关键点就是:

* 区分出shell m eta 与command meta

前面我们提到的那些meta ,都是在command line 中有特殊用途的,

比方说{ } 是将其内一系列command line 置於不具名的函式中执行(可简单视为command block ),但是,awk 却需要用{ } 来区分出awk 的命令区段(BEGIN, MAIN, END)。

若你在command line 中如此输入:

CODE:

$ awk {print $0} 1.txt

由於 { } 在shell 中并没关闭,那shell 就将{print $0} 视为command block ,

但同时又没有" ; "符号作命令区隔,因此就出现awk 的语法错误结果。

要解决之,可用hard quote :

CODE:

$ awk '{print $0}' 1.txt

上面的hard quote 应好理解,就是将原本的{、、$(注三)、} 这几个shell m eta 关闭,

避免掉在shell 中遭到处理,而完整的成为awk 参数中的command meta 。

( 注三:而其中的$0 是awk 内置的field number ,而非 awk 的变量,

awk 自身的变量无需使用$ 。)

要是理解了hard quote 的功能,再来理解soft quote 与escape 就不难:

CODE:

awk "{print \$0}" 1.txt

awk \{print\ \$0\} 1.txt

然而,若你要改变awk 的$0 的0 值是从另一个shell 变量读进呢?

比方说:已有变量$A 的值是0 ,那如何在command line 中解决awk 的$$A 呢?

你可以很直接否定掉hard quoe 的方案:

CODE:

$ awk '{print $$A}' 1.txt

那是因为$A 的$ 在hard quote 中是不能替换变量的。

聪明的读者(如你!),经过本章学习,我想,应该可以解释为何我们可以使用如下操作了吧:

CODE:

A=0

awk "{print \$$A}" 1.txt

awk \{print\ \$$A\} 1.txt

awk '{print $'$A'}' 1.txt

awk '{print $'"$A"'}' 1.txt # 注:"$A" 包在soft quote 中

或许,你能举出更多的方案呢.... ^_^

--------------------------------------

练习与思考:请运用本章学到的知识分析如下两串讨论:

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=207178

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=216729

--------------------------------------

5) var=value?export 前后差在哪?

这次让我们暂时丢开command line ,先来了解一下bash 变量(variable)吧...

所谓的变量,就是就是利用一个特定的"名称"(name)来访问一段可以变化的"值"(value)。

*设置(set)*

在bash 中,你可以用"=" 来设置或重新定义变量的内容:

nam e=value

在设置变量的时侯,得遵守如下规则:

* 等号左右两边不能使用区隔符号(IFS),也应避免使用shell 的保留字符(meta charactor)。

* 变量名称不能使用$ 符号。

* 变量名称的第一个字母不能是数字(number)。

* 变量名称长度不可超过256 个字母。

* 变量名称及变量值之尺寸写是有区别的(case sensitive)。

如下是一些变量设置时常见的错误:

A= B :不能有IFS

1A=B :不能以数字开头

$A=B :名称不能有$

a=B :这跟a=b 是不同的

如下则是可以接受的设置:

A=" B" :IFS 被关闭了(请参考前面的quoting 章节)

A1=B :并非以数字开头

A=$B :$ 可用在变量值内

This_Is_A_Long_Name=b :可用_ 连接较长的名称或值,且尺寸写有别。

*变量替换(substitution)*

Shell 之所以强大,其中的一个因素是它可以在命令行中对变量作替换(substitution)处理。

在命令行中用户可以使用$ 符号加上变量名称(除了在用=号定义变量名称之外),

将变量值给替换出来,然后再重新组建命令行。

比如:

CODE:

$ A=ls

$ B=la

$ C=/t mp

$ $A -$B $C

(注意:以上命令行的第一个$ 是shell prompt ,并不在命令行之内。)

必需强调的是,我们所提的变量替换,只发生在command line 上面。(是的,让我们再回到command line 吧!) 仔细分析最后那行command line ,不难发现在被执行之前(在输入CR 字符之前),

$ 符号会对每一个变量作替换处理(将变量值替换出来再重组命令行),最后会得出如下命令行:

CODE:

ls -la /tm p

还记得第二章我请大家"务必理解"的那两句吗?若你忘了,那我这里再重贴一遍:

QUOTE:

若从技术细节来看,shell 会依据IFS(Internal Field Seperator) 将comm and line 所输入的文字给拆解为"字段"(word)。

然后再针对特殊字符(meta)先作处理,最后再重组整行command line 。

这里的$ 就是command line 中最经典的meta 之一了,就是作变量替换的!

在日常的shell 操作中,我们常会使用echo 命令来查看特定变量的值,例如:

我们已学过,echo 命令只单纯将其argument 送至"标准输出"(STDOUT,通常是我们的荧幕)。所以上面的命令会在荧幕上得到如下结果:

CODE:

ls -la /tm p

这是由於echo 命令在执行时,会先将$A(ls)、$B(la)、跟$C(/t mp) 给替换出来的结果。

利用shell 对变量的替换处理能力,我们在设置变量时就更为灵活了:

A=B

B=$A

这样,B 的变量值就可继承 A 变量"当时"的变量值了。

不过,不要以"数学罗辑"来套用变量的设置,比方说:

A=B

B=C

这样并不会让 A 的变量值变成 C 。再如:

A=B

B=$A

A=C

同样也不会让 B 的值换成 C 。

上面是单纯定义了两个不同名称的变量:A 与 B ,它们的值分别是 B 与 C 。

若变量被重复定义的话,则原有旧值将被新值所取代。(这不正是"可变的量"吗? ^_^)

当我们在设置变量的时侯,请记著这点:

* 用一个名称存储一个数值

仅此而已。

此外,我们也可利用命令行的变量替换能力来"扩充"(append)变量值:

A=B:C:D

A=$A:E

这样,第一行我们设置 A 的值为"B:C:D",然后,第二行再将值扩充为"B:C:D:E" 。

上面的扩充样例,我们使用区隔符号( : )来达到扩充目的,

要是没有区隔符号的话,如下是有问题的:

A=BCD

A=$AE

因为第二次是将 A 的值继承$AE 的提换结果,而非$A 再加 E ﹗

要解决此问题,我们可用更严谨的替换处理:

A=BCD

A=${A}E

上例中,我们使用{} 将变量名称的范围给明确定义出来,

如此一来,我们就可以将 A 的变量值从BCD 给扩充为BCDE 。

(提示:关于${name} 事实上还可做到更多的变量处理能力,这些均属于比较高级的变量处理,现阶段暂时不介绍了,请大家自行参考数据。如CU 的贴子:

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=201843

)

* export *

严格来说,我们在当前shell 中所定义的变量,均属於"本地变量"(local variable),

只有经过export 命令的"输出"处理,才能成为环境变量(environment variable):

CODE:

$ A=B

$ export A

或:

CODE:

$ export A=B

经过export 输出处理之后,变量 A 就能成为一个环境变量供其后的命令使用。

在使用export 的时侯,请别忘记shell 在命令行对变量的"替换"(substitution)处理,

比方说:

CODE:

$ A=B

$ B=C

$ export $A

上面的命令并未将 A 输出为环境变量,而是将 B 作输出,

这是因为在这个命令行中,$A 会首先被提换出 B 然后再"塞回"作export 的参数。

要理解这个export ,事实上需要从process 的角度来理解才能透彻。

我将於下一章为大家说明process 的观念,敬请留意。

*取消变量*

要取消一个变量,在bash 中可使用unset 命令来处理:

CODE:

unset A

与export 一样,unset 命令行也同样会作变量替换(这其实就是shell 的功能之一),

因此:

CODE:

$ A=B

$ B=C

$ unset $A

事实上所取消的变量是 B 而不是 A 。

此外,变量一旦经过unset 取消之后,其结果是将整个变量拿掉,而不仅是取消其变量值。

如下两行其实是很不一样的:

CODE:

$ A=

$ unset A

第一行只是将变量 A 设置为"空值"(null value),但第二行则让变量 A 不在存在。

虽然用眼睛来看,这两种变量状态在如下命令结果中都是一样的:

CODE:

$ A=

$ echo $A

$ unset A

$ echo $A

请学员务必能标识null value 与unset 的本质区别,这在一些高级的变量处理上是很严格的。比方说:

CODE:

$ echo $var

$ echo $str

$ unset str # 取消

$ var=${str=expr} # 定义var

$ echo $var

expr

$ echo $str

expr

聪明的读者(yes, you!),稍加思考的话,

应该不难发现为何同样的var=${str=expr} 在null 与unset 之下的不同吧?

若你看不出来,那可能是如下原因之一:

a. 你太笨了

b. 不了解 var=${str=expr} 这个高级处理

c. 对本篇说明还没来得及消化吸收

e. 我讲得不好

不知,你选哪个呢?.... ^_^

6) exec 跟source 差在哪?

这次先让我们从CU Shell 版的一个实例贴子来谈起吧:

( https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=194191 )

例中的提问是:

QUOTE:

cd /etc/aa/bb/cc可以执行

但是把这条命令写入shell时shell不执行!

这是什么原因呀!

我当时如何回答暂时别去深究,先让我们了解一下进程(process)的观念好了。

首先,我们所执行的任何程序,都是由父进程(parent process)所产生出来的一个子进程(child process),

子进程在结束后,将返回到父进程去。此一现像在Linux 系统中被称为 fork 。

(为何要程为fork 呢?嗯,画一下图或许比较好理解... ^_^ )

当子进程被产生的时候,将会从父进程那里获得一定的资源配置、及(更重要的是)继承父进程的环境!

让我们回到上一章所谈到的"环境变量"吧:

* 所谓环境变量其实就是那些会传给子进程的变量。

简单而言,"遗传性"就是区分本地变量与环境变量的决定性指标。

然而,从遗传的角度来看,我们也不难发现环境变量的另一个重要特征:

* 环境变量只能从父进程到子进程单向继承。换句话说:在子进程中的环境如何更改,均不会影响父进程的环境。

接下来,再让我们了解一下命令脚本(shell script)的概念。

所谓的shell script 讲起来很简单,就是将你平时在shell prompt 后所输入的多行command line 依序写入一个文件去而已。

其中再加上一些条件判断、交互界面、参数运用、函数调用、等等技巧,得以让script 更加"聪明"的执行,

但若撇开这些技巧不谈,我们真的可以简单的看成script 只不过依次执行预先写好的命令行而已。

再结合以上两个概念(process + script),那应该就不难理解如下这句话的意思了:

* 正常来说,当我们执行一个shell script 时,其实是先产生一个sub-shell 的子进程,然后sub-shell 再去产生命令行的子进程。

然则,那让我们回到本章开始时所提到的例子再重新思考:

QUOTE:

cd /etc/aa/bb/cc可以执行

但是把这条命令写入shell时shell不执行!

这是什么原因呀!

我当时的答案是这样的:

QUOTE:

因为,一般我们跑的shell script 是用subshell 去执行的。

从process 的观念来看,是parent process 产生一个child process 去执行,

当child 结束后,会返回parent ,但parent 的环境是不会因child 的改变而改变的。

所谓的环境元数很多,凡举effective id, variable, workding dir 等等...

其中的workding dir ($PWD) 正是楼主的疑问所在:

当用subshell 来跑script 的话,sub shell 的$PWD 会因为cd 而更改,

但当返回primary shell 时,$PWD 是不会更改的。

能够了解问题的原因及其原理是很好的,但是?如何解决问题恐怕是我们更感兴趣的!是吧?^_^

那好,接下来,再让我们了解一下source 命令好了。

当你有了fork 的概念之后,要理解source 就不难:

* 所谓source 就是让script 在当前shell 内执行、而不是产生一个sub-shell 来执行。

由於所有执行结果均於当前shell 内完成,若script 的环境有所改变,当然也会改变当前环境了!

因此,只要我们要将原本单独输入的script 命令行变成source 命令的参数,就可轻易解决前例提到的问题了。比方说,原本我们是如此执行 script 的:

CODE:

./m y.script

现在改成这样即可:

CODE:

source ./m y.script

或:

. ./m y.script

说到这里,我想,各位有兴趣看看/etc 底下的众多设置文件,

应该不难理解它们被定议后,如何让其它script 读入并继承了吧?

若然,日后你有机会写自己的script ,应也不难专门指定一个设置文件以供不同的script 一起"共享"了... ^_^

okay,到这里,若你搞得懂fork 与source 的不同,那接下来再接受一个挑战:

---- 那exec 又与source/fork 有何不同呢?

哦... 要了解exec 或许较为复杂,尤其扯上File Descriptor 的话...

不过,简单来说:

* exec 也是让script 在同一个进程上执行,但是原有进程则被结束了。

也就是简而言之:原有进程会否终止,就是exec 与source/fork 的最大差异了。

嗯,光是从理论去理解,或许没那么好消化,不如动手"实作+思考"来的印像深刻哦。

下面让我们写两个简单的script ,分别命令为 1.sh 及 2.sh :

1.sh

CODE:

#!/bin/bash

A=B

echo "PID for 1.sh before exec/source/fork:$$"

export A

echo "1.sh: \$A is $A"

case $1 in

exec)

echo "using exec..."

exec ./2.sh ;;

source)

*)

echo "using fork by default..."

./2.sh ;;

esac

echo "PID for 1.sh after exec/source/fork:$$"

echo "1.sh: \$A is $A"

2.sh

CODE:

#!/bin/bash

echo "PID for 2.sh: $$"

echo "2.sh get \$A=$A from 1.sh"

A=C

export A

echo "2.sh: \$A is $A"

然后,分别跑如下参数来观察结果:

CODE:

$ ./1.sh fork

$ ./1.sh source

$ ./1.sh exec

或是,你也可以参考CU 上的另一贴子:

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=191051

好了,别忘了仔细比较输出结果的不同及背后的原因哦...

若有疑问,欢迎提出来一起讨论讨论~~~

happy scripting! ^_^

7) ( ) 与{ } 差在哪?

嗯,这次轻松一下,不讲太多... ^_^

先说一下,为何要用( ) 或{ } 好了。

许多时候,我们在shell 操作上,需要在一定条件下一次执行多个命令,

也就是说,要么不执行,要么就全执行,而不是每次依序的判断是否要执行下一个命令。

或是,需要从一些命令执行优先次顺中得到豁免,如算术的2*(3+4) 那样...

这时候,我们就可引入"命令群组"(command group)的概念:将多个命令集中处理。

在shell command line 中,一般人或许不太计较( ) 与{ } 这两对符号的差异,

虽然两者都可将多个命令作群组化处理,但若从技术细节上,却是很不一样的:

( ) 将command group 置於sub-shell 去执行,也称nested sub-shell。

{ } 则是在同一个shell 内完成,也称为non-nam ed command group。

若,你对上一章的fork 与source 的概念还记得了的话,那就不难理解两者的差异了。

要是在command group 中扯上变量及其它环境的修改,我们可以根据不同的需求来使用( ) 或{ } 。

通常而言,若所作的修改是临时的,且不想影响原有或以后的设置,那我们就nested sub-shell ,

反之,则用non-named command group 。

是的,光从comm and line 来看,( ) 与{ } 的差别就讲完了,够轻松吧~~~ ^_^

然而,若这两个meta 用在其它command meta 或领域中(如Regular Expression),还是有很多差别的。只是,我不打算再去说明了,留给读者自己慢慢发掘好了...

我这里只想补充一个概念,就是function 。

所谓的function ,就是用一个名字去命名一个 command group ,然后再调用这个名字去执行command group 。

在bash 中,function 的定义方式有两种:

方式一:

CODE:

function function_name {

command1

command2

command3

....

}

方式二:

CODE:

fuction_name () {

command1

command2

command3

....

}

用哪一种方式无所谓,只是若碰到所定意的名称与现有的命令或别名(Alias)冲突的话,方式二或许会失败。

但方式二起码可以少打function 这一串英文字母,对懒人来说(如我),又何乐不为呢?... ^_^

function 在某一程度来说,也可称为"函数",但请不要与传统编程所使用的函数库(library)搞混了,毕竟两者差异很大。

惟一相同的是,我们都可以随时用"已定义的名称"来调用它们...

若我们在shell 操作中,需要不断的重覆执行某些命令,我们首先想到的,或许是将命令写成shell脚本(shell script)。

不过,我们也可以写成function ,然后在command line 中打上function_name 就可当一般的script 来使用了。

只是若你在shell 中定义的function ,除了可用unset function_name 取消外,一旦退出shell ,function 也跟著取消。

然而,在script 中使用function 却有许多好处,除了可以提高整体script 的执行性能外(因为已被装入),

还可以节省许多重复的代码...

简单而言,若你会将多个命令写成script 以供调用的话,那,你可以将function 看成是script 中的

script ... ^_^

而且,通过上一章介绍的source 命令,我们可以自行定义许许多多好用的function ,再集中写在特定文件中,

然后,在其它的script 中用source 将它们装入并反复执行。

若你是RedHat Linux 的用户,或许,已经猜得出/etc/rc.d/init.d/functions 这个文件是作啥用的了~~~ ^_^ okay,说要轻松点的嘛,那这次就暂时写到这吧。祝大家学习愉快! ^_^

8) $(( )) 与$( ) 还有${ } 差在哪?

我们上一章介绍了( ) 与{ } 的不同,这次让我们扩展一下,看看更多的变化:$( ) 与${ } 又是啥玩意儿呢?

在bash shell 中,$( ) 与` ` (反引号) 都是用来做命令替换用(command substitution)的。

所谓的命令替换与我们第五章学过的变量替换差不多,都是用来重组命令行:

* 完成引号里的命令行,然后将其结果替换出来,再重组命令行。

例如:

[code]$ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)[/code]

如此便可方便得到上一星期天的日期了... ^_^

1, ` ` 很容易与' ' ( 单引号)搞混乱,尤其对初学者来说。

有时在一些奇怪的字形显示中,两种符号是一模一样的(直竖两点)。

当然了,有经验的朋友还是一眼就能分辩两者。只是,若能更好的避免混乱,又何乐不为呢?^_^

2, 在多层次的复合替换中,` ` 须要额外的跳脱( \` )处理,而$( ) 则比较直观。例如:

这是错的:

[code]command1 `command2 `command3` `[/code]

原本的意图是要在command2 `command3` 先将command3 提换出来给command 2 处理,然后再将结果传给command1 `command2 ...` 来处理。

然而,真正的结果在命令行中却是分成了`command2 ` 与`` 两段。

正确的输入应该如下:

[code]command1 `command2 \`command3\` `[/code]

要不然,换成$( ) 就没问题了:

[code]command1 $(command2 $(command3))[/code]

只要你喜欢,做多少层的替换都没问题啦~~~ ^_^

不过,$( ) 并不是没有毙端的...

首先,` ` 基本上可用在全部的unix shell 中使用,若写成shell script ,其移植性比较高。

而$( ) 并不见的每一种shell 都能使用,我只能跟你说,若你用bash2 的话,肯定没问题... ^_^

接下来,再让我们看${ } 吧... 它其实就是用来作变量替换用的啦。

一般情况下,$var 与${var} 并没有啥不一样。

但是用${ } 会比较精确的界定变量名称的范围,比方说:

[code]$ A=B

$ echo $AB

[/code]

原本是打算先将$A 的结果替换出来,然后再补一个 B 字母於其后,

但在命令行上,真正的结果却是只会提换变量名称为AB 的值出来...

若使用${ } 就没问题了:

[code]$ echo ${A}B

BB[/code]

不过,假如你只看到${ } 只能用来界定变量名称的话,那你就实在太小看bash 了!

有兴趣的话,你可先参考一下cu 本版的精华文章:

https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=201843

为了完整起见,我这里再用一些例子加以说明${ } 的一些特异功能:

假设我们定义了一个变量为:

file=/dir1/dir2/dir3/m y.file.txt

我们可以用${ } 分别替换获得不同的值:

${file#*/}:拿掉第一条/ 及其左边的符串:dir1/dir2/dir3/my.file.txt

${file##*/}:拿掉最后一条/ 及其左边的符串:my.file.txt

${file#*.}:拿掉第一个 . 及其左边的符串:file.txt

${file##*.}:拿掉最后一个 . 及其左边的符串:txt

${file%/*}:拿掉最后条/ 及其右边的符串:/dir1/dir2/dir3

${file%%/*}:拿掉第一条/ 及其右边的符串:(空值)

${file%.*}:拿掉最后一个 . 及其右边的符串:/dir1/dir2/dir3/my.file

${file%%.*}:拿掉第一个 . 及其右边的符串:/dir1/dir2/dir3/my

记忆的方法为:

[list]# 是去掉左边(在鉴盘上# 在$ 之左边)

% 是去掉右边(在鉴盘上% 在$ 之右边)

单一符号是最小匹配;两个符号是最大匹配。[/list]

${file:0:5}:提取最左边的5 个字节:/dir1

${file:5:5}:提取第5 个字节右边的连续5 个字节:/dir2

我们也可以对变量值里的符串作替换:

${file/dir/path}:将第一个dir 提换为path:/path1/dir2/dir3/my.file.txt

${file//dir/path}:将全部dir 提换为path:/path1/path2/path3/my.file.txt

利用${ } 还可针对不同的变量状态赋值(没设置、空值、非空值):

${file-m y.file.txt} :假如$file 没有设置,则使用my.file.txt 作返回值。(空值及非空值时不作处理)

${file:-m y.file.txt} :假如$file 没有设置或为空值,则使用my.file.txt 作返回值。(非空值时不作处理) ${file+my.file.txt} :假如$file 设为空值或非空值,均使用my.file.txt 作返回值。(没设置时不作处理) ${file:+my.file.txt} :若$file 为非空值,则使用my.file.txt 作返回值。(没设置及空值时不作处理)

${file=my.file.txt} :若$file 没设置,则使用my.file.txt 作返回值,同时将$file 赋值为my.file.txt 。(空值及非空值时不作处理)

${file:=my.file.txt} :若$file 没设置或为空值,则使用my.file.txt 作返回值,同时将$file 赋值为

my.file.txt 。(非空值时不作处理)

${file?my.file.txt} :若$file 没设置,则将my.file.txt 输出至STDERR。(空值及非空值时不作处理) ${file:?my.file.txt} :若$file 没设置或为空值,则将m y.file.txt 输出至STDERR。(非空值时不作处理) tips:

以上的理解在於, 你一定要分清楚unset 与null 及non-null 这三种赋值状态.

一般而言, : 与null 有关, 若不带: 的话, null 不受影响, 若带: 则连null 也受影响.

还有哦,${#var} 可计算出变量值的长度:

${#file} 可得到27 ,因为/dir1/dir2/dir3/my.file.txt 刚好是27 个字节...

接下来,再为大家介稍一下bash 的组数(array)处理方法。

一般而言,A="a b c def" 这样的变量只是将$A 替换为一个单一的符串,

但是改为A=(a b c def) ,则是将$A 定义为组数...

bash 的组数替换方法可参考如下方法:

${A[@]} 或${A[*]} 可得到a b c def (全部组数)

${A[0]} 可得到a (第一个组数),${A[1]} 则为第二个组数...

${#A[@]} 或${#A[*]} 可得到4 (全部组数数量)

${#A[0]} 可得到1 (即第一个组数(a)的长度),${#A[3]} 可得到 3 (第四个组数(def)的长度)

A[3]=xyz 则是将第四个组数重新定义为xyz ...

诸如此类的....

能够善用bash 的$( ) 与${ } 可大大提高及简化shell 在变量上的处理能力哦~~~ ^_^

好了,最后为大家介绍$(( )) 的用途吧:它是用来作整数运算的。

在bash 中,$(( )) 的整数运算符号大致有这些:

+ - * / :分别为"加、减、乘、除"。

% :余数运算

& | ^ !:分别为"AND、OR、XOR、NOT" 运算。

例:

[code]$ a=5; b=7; c=2

$ echo $(( a+b*c ))

19

$ echo $(( (a+b)/c ))

6

$ echo $(( (a*b)%c))

1[/code]

在$(( )) 中的变量名称,可於其前面加$ 符号来替换,也可以不用,如:

$(( $a + $b * $c)) 也可得到19 的结果

此外,$(( )) 还可作不同进制(如二进制、八进制、十六进制)作运算呢,只是,输出结果皆为十进制而已:

以一个实用的例子来看看吧:

假如当前的 umask 是022 ,那么新建文件的权限即为:

[code]$ um ask 022

$ echo "obase=8;$(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc

644[/code]

事实上,单纯用(( )) 也可重定义变量值,或作testing:

a=5; ((a++)) 可将$a 重定义为6

a=5; ((a--)) 则为a=4

a=5; b=7; ((a < b)) 会得到 0 (true) 的返回值。

常见的用於(( )) 的测试符号有如下这些:

[list]<:小於

>:大於

<=:小於或等於

>=:大於或等於

==:等於

!=:不等於[/list]

不过,使用(( )) 作整数测试时,请不要跟[ ] 的整数测试搞混乱了。(更多的测试我将於第十章为大家介绍)

怎样?好玩吧.. ^_^ okay,这次暂时说这么多...

上面的介绍,并没有详列每一种可用的状态,更多的,就请读者参考手册文件罗...

9) $@ 与$* 差在哪?

要说$@ 与$* 之前,需得先从shell script 的positional parameter 谈起...

我们都已经知道变量(variable)是如何定义及替换的,这个不用再多讲了。

但是,我们还需要知道有些变量是shell 内定的,且其名称是我们不能随意修改的,

其中就有positional parameter 在内。

在shell script 中,我们可用$0, $1, $2, $3 ... 这样的变量分别提取命令行中的如下部份:

CODE:

script_name parameter1 parameter2 parameter3 ...

我们很容易就能猜出$0 就是代表shell script 名称(路迳)本身,而$1 就是其后的第一个参数,如此类推....

须得留意的是IFS 的作用,也就是,若IFS 被quoting 处理后,那么positional parameter 也会改变。

如下例:

CODE:

my.sh p1 "p2 p3" p4

由於在p2 与p3 之间的空白键被soft quote 所关闭了,因此my.sh 中的$2 是"p2 p3" 而$3 则是p4 ...

还记得前两章我们提到fucntion 时,我不是说过它是script 中的script 吗? ^_^

是的,function 一样可以读入自己的(有别於script 的) postitional param eter ,惟一例外的是$0 而已。

举例而言:假设my.sh 里有一个fucntion 叫my_fun , 若在script 中跑my_fun fp1 fp2 fp3 ,

那么,function 内的$0 是my.sh ,而$1 则是fp1 而非p1 了...

不如写个简单的my.sh script 看看吧:

CODE:

#!/bin/bash

my_fun() {

echo '$0 inside function is '$0

echo '$1 inside function is '$1

echo '$2 inside function is '$2

echo '$0 outside function is '$0

echo '$1 outside function is '$1

echo '$2 outside function is '$2

my_fun fp1 "fp2 fp3"

然后在command line 中跑一下script 就知道了:

CODE:

chm od +x my.sh

./m y.sh p1 "p2 p3"

$0 outside function is ./m y.sh

$1 outside function is p1

$2 outside function is p2 p3

$0 inside function is ./m y.sh

$1 inside function is fp1

$2 inside function is fp2 fp3

然而,在使用positional parameter 的时候,我们要注意一些陷阱哦:

* $10 不是替换第10 个参数,而是替换第一个参数($1)然后再补一个0 於其后!

也就是,my.sh one two three four five six seven eigth nine ten 这样的command line ,my.sh 里的$10 不是ten 而是one0 哦... 小心小心!

要抓到ten 的话,有两种方法:

方法一是使用我们上一章介绍的${ } ,也就是用${10} 即可。

方法二,就是shift 了。

用通俗的说法来说,所谓的shift 就是取消positional parameter 中最左边的参数( $0 不受影响)。其缺省值为 1 ,也就是shift 或shift 1 都是取消$1 ,而原本的$2 则变成$1、$3 变成$2 ... 若shift 3 则是取消前面三个参数,也就是原本的$4 将变成$1 ...

那,亲爱的读者,你说要shift 掉多少个参数,才可用$1 取得${10} 呢?^_^

okay,当我们对positional parameter 有了基本概念之后,那再让我们看看其它相关变量吧。

首先是$# :它可抓出positional parameter 的数量。

以前面的my.sh p1 "p2 p3" 为例:

由於p2 与p3 之间的IFS 是在soft quote 中,因此$# 可得到 2 的值。

但如果p2 与p3 没有置於quoting 中话,那$# 就可得到 3 的值了。

同样的道理在function 中也是一样的...

因此,我们常在shell script 里用如下方法测试script 是否有读进参数:

CODE:

[ $# = 0 ]

假如为0 ,那就表示script 没有参数,否则就是有带参数...

接下来就是$@ 与$* :

精确来讲,两者只有在soft quote 中才有差异,否则,都表示"全部参数"( $0 除外)。

举例来说好了:

若在command line 上跑my.sh p1 "p2 p3" p4 的话,

不管是$@ 还是$* ,都可得到p1 p2 p3 p4 就是了。

但是,如果置於soft quote 中的话:

"$@" 则可得到"p1" "p2 p3" "p4" 这三个不同的词段(word)﹔

"$*" 则可得到"p1 p2 p3 p4" 这一整串单一的词段。

我们可修改一下前面的my.sh ,使之内容如下:

CODE:

#!/bin/bash

my_fun() {

echo "$#"

}

echo 'the num ber of parameter in "$@" is '$(m y_fun "$@")

echo 'the num ber of parameter in "$*" is '$(my_fun "$*")

然后再执行 ./m y.sh p1 "p2 p3" p4 就知道$@ 与$* 差在哪了 ... ^_^

10) && 与|| 差在哪?

好不容易,进入两位数的章节了... 一路走来,很辛苦吧?也很快乐吧? ^_^

在解答本章题目之前,先让我们了解一个概念:return value ﹗

我们在shell 下跑的每一个command 或function ,在结束的时候都会返回父进程一个值,称为return value 。在shell command line 中可用$? 这个变量得到最"新"的一个return value ,也就是刚结束的那个进程返回的值。

Return Value(RV) 的取值为0-255 之间,由程序(或script)的作者自行定议:

* 若在script 里,用exit RV 来指定其值,若没指定,在结束时以最后一道命令之RV 为值。

* 若在function 里,则用return RV 来代替exit RV 即可。

Return Value 的作用,是用来判断进程的退出状态(exit status),只有两种:

* 0 的话为"真"( true )

* 非 0 的话为"假"( false )

举个例子来说明好了:

假设当前目录内有一份my.file 的文件,而no.file 是不存在的:

CODE:

$ touch m y.file

$ ls m y.file

$ echo $? # first echo

$ ls no.file

ls: no.file: No such file or directory

$ echo $? # second echo

1

$ echo $? # third echo

上例的第一个echo 是关于ls my.file 的RV ,可得到0 的值,因此为true ﹔

第二个echo 是关于ls no.file 的RV ,则得到非0 的值,因此为false ﹔

第三个echo 是关于第二个echo $? 的RV ,为0 的值,因此也为true 。

请记住:每一个command 在结束时都会送回return value 的!不管你跑甚么样的命令...

然而,有一个命令却是"专门"用来测试某一条件而送出return value 以供true 或false 的判断,

它就是test 命令了!

若你用的是bash ,请在command line 下打man test 或m an bash 来了解这个test 的用法。

这是你可用作参考的最精确的文件了,要是听别人说的,仅作参考就好...

下面我只简单作一些帮助,额外的一律以man 为准:

首先,test 的表达式我们称为expression ,其命令格式有两种:

CODE:

or:

[ expression ]

(请务必注意[ ] 之间的空白键!)

用哪一种格式没所谓,都是一样的效果。(我个人比较喜欢后者...)

其次,bash 的test 当前支持的测试对像只有三种:

* string:符串,也就是纯文本。

* integer:整数( 0 或正整数,不含负数或小数点)。

* file:文件。

请初学者一定要搞清楚这三者的差异,因为test 所用的expression 是不一样的。

以A=123 这个变量为例:

* [ "$A" = 123 ]:是符串的测试,以测试$A 是否为1、2、3 这三个连续的"文字"。

* [ "$A" -eq 123 ]:是整数的测试,以测试$A 是否等於"一百二十三"。

* [ -e "$A" ]:是关于文件的测试,以测试123 这份"文件"是否存在。

第三,当expression 测试为"真"时,test 就送回0 (true) 的return value ,否则送出非0 (false)。

若在expression 之前加上一个" ! "(感叹号),则是当expression 为"假时" 才送出0 ,否则送出非0 。

同时,test 也允许多重的复合测试:

* expression1 -a expression2 :当两个exrepssion 都为true ,才送出0 ,否则送出非0 。

* expression1 -o expression2 :只需其中一个exrepssion 为true ,就送出0 ,只有两者都为false 才送出非0 。

例如:

CODE:

[ -d "$file" -a -x "$file" ]

是表示当$file 是一个目录、且同时具有x 权限时,test 才会为true 。

第四,在command line 中使用test 时,请别忘记命令行的"重组"特性,

也就是在碰到meta 时会先处理meta 再重新组建命令行。(这个特性我在第二及第四章都曾反复强调过)

比方说,若test 碰到变量或命令替换时,若不能满足expression 格式时,将会得到语法错误的结果。

举例来说好了:

关于[ string1 = string2 ] 这个test 格式,

在=号两边必须要有符串,其中包括空(null)符串(可用soft quote 或hard quote 取得)。

假如$A 当前没有定义,或被定议为空符串的话,那如下的写法将会失败:

CODE:

$ unset A

$ [ $A = abc ]

[: =: unary operator expected

这是因为命令行碰到 $ 这个meta 时,会替换$A 的值,然后再重组命令行,那就变成了:

[ = abc ]

如此一来= 号左边就没有符串存在了,因此造成test 的语法错误!

但是,下面这个写法则是成立的:

CODE:

$ [ "$A" = abc ]

$ echo $?

1

这是因为在命令行重组后的结果为:

[ "" = abc ]

由於=左边我们用soft quote 得到一个空符串,而让test 语法得以通过...

shell 十三问

?1) 為何叫做 shell ? 在介紹 shell 是甚麼東西之前,不妨讓我們重新檢視使用者與電腦系統的關係: 圖(FIXME) 我們知道電腦的運作不能離開硬體,但使用者卻無法直接對硬體作驅動, 硬體的驅動只能透過一個稱為"作業系統(Operating System)"的軟體來控管, 事實上,我們每天所談的 linux ,嚴格來說只是一個作業系統,我們稱之為"核心(kernel)"。 然而,從使用者的角度來說,使用者也沒辦法直接操作 kernel , 而是透過 kernel 的"外殼"程式,也就是所謂的 shell ,來與 kernel 溝通。 這也正是 kernel 跟 shell 的形像命名關係。如圖: 圖(FIXME) 從技術角度來說,shell 是一個使用者與系統的互動界面(interface), 主要是讓使用者透過命令行(command line)來使用系統以完成工作。 因此,shell 的最簡單的定義就是---命令解譯器(Command Interpreter):* 將使用者的命令翻譯給核心處理, * 同時,將核心處理結果翻譯給使用者。 每次當我們完成系統登入(log in),我們就取得一個互動模式的 shell ,也稱為 login shell 或 primary shell。 若從行程(process)角度來說,我們在 shell 所下達的命令,均是 shell 所產生的子行程。這現像,我們暫可稱之為 fork 。 如果是執行腳本(shell script)的話,腳本中的命令則是由另外一個非互動模式的子 shell (sub shell)來執行的。 也就是 primary shell 產生 sub shell 的行程,sub shell 再產生 script 中所有命令 的行程。(關於行程,我們日後有機會再補充。) 這裡,我們必須知道:kernel 與 shell 是不同的兩套軟體,而且都是可以被替換的:

命令脚本(shell script)的概念

Shell 十三问 作者:https://www.wendangku.net/doc/745023933.html,之網中人 详细讨论在: https://www.wendangku.net/doc/745023933.html,/forum/viewtopic.php?t=218853&postdays=0&postorder=asc&start=0 1) 为何叫做shell ? 在介绍shell 是甚么东西之前,不妨让我们重新检视使用者与计算机系统的关系: 图(FIXME) 我们知道计算机的运作不能离开硬件,但使用者却无法直接对硬件作驱动, 硬件的驱动只能透过一个称为"操作系统(Operating System)"的软件来控管, 事实上,我们每天所谈的linux ,严格来说只是一个操作系统,我们称之为"核心(kernel)"。然而,从使用者的角度来说,使用者也没办法直接操作kernel , 而是透过kernel 的"外壳"程序,也就是所谓的shell ,来与kernel 沟通。 这也正是kernel 跟shell 的形像命名关系。如图: 图(FIXME) 从技术角度来说,shell 是一个使用者与系统的互动界面(interface), 主要是让使用者透过命令行(command line)来使用系统以完成工作。 因此,shell 的最简单的定义就是---命令解译器(Command Interpreter): * 将使用者的命令翻译给核心处理, * 同时,将核心处理结果翻译给使用者。 每次当我们完成系统登入(log in),我们就取得一个互动模式的shell ,也称为login shell 或primary shell。 若从行程(process)角度来说,我们在shell 所下达的命令,均是shell 所产生的子行程。这现像,我们暂可称之为fork 。 如果是执行脚本(shell script)的话,脚本中的命令则是由另外一个非互动模式的子shell (sub shell)来执行的。 也就是primary shell 产生sub shell 的行程,sub shell 再产生script 中所有命令的行程。(关于行程,我们日后有机会再补充。) 这里,我们必须知道:kernel 与shell 是不同的两套软件,而且都是可以被替换的: * 不同的操作系统使用不同的kernel , * 而在同一个kernel 之上,也可使用不同的shell 。 在linux 的预设系统中,通常都可以找到好几种不同的shell ,且通常会被列于如下档案里:/etc/shells 不同的shell 有着不同的功能,且也彼此各异、或说"大同小异"。 常见的shell 主要分为两大主流: sh: burne shell (sh)

习题07_Shell编程

习题07_Shell编程 一、单选 1. 下面哪个命令是用来定义shell的全局变量( D )。 A. exportfs B. alias C. exports D. export 2.在Shell脚本中,用来读取文件内各个域的内容并将其赋值Shell变量的命令是(D )。 A. fold B. join C. tr D. read 3. 当字符串用双引号(’’)括起来时,SHELL将(C )。 A. 解释引号内的特殊字符 B. 执行引号中的命令 C. 不解释引号内的特殊字符 D. 结束进程 4. 以下哪个环境变量表示当前路径( B )。 A. PATH B. PWD C. HOME D. ROOT 5. shell不仅是(用户命令的解释器),它同时也是一种功能强大的编程语言,(bash )是Linux的缺省shell。 6. 编写的Shell程序运行前必须赋予该脚本文件(执行)权限。 7. 对于Shell脚本程序,若输入参数数量多于9个,则程序遍历每个参数可通过使用(shift )命令实现。 8. 为脚本程序指定执行权的命令及参数是( chmod a+x filename )。 9. 在shell编程时,使用方括号表示测试条件的规则是:方括号两边必有(空格)。 10. 输入了Shell命令的部分字符后按( tab )键可补全其余部分。 11.改变命令提示符的环境变量是(PS1 )。 11. grep -E '[Hh]enr(y|ietta)' file的功能是:(在文件File中查找Henry、henry、Henrietta或henrietta)。 12. 如下为命令终端下的一个截图: 则,以下两句的执行结果是:(the home path is $HOME )。 path=‘the home path is $HOME’ echo $path 13. 以下为程序名为prog的程序内容。则sh prog a b c d的执行结果为( C )。 set A B C D shift shift echo $1 三、简答 1. 下面给出了一个SHELL程序,试对其行后有#(n)形式的语句进行解释,并说明程序完成的功能。

shell操作字符串

SHELL的字符替换 SHELL的字符替换 shell的字符替换 变量替换: 一:简单赋值和替换 a=bcd $ echo $a bcd $ echo ${a} ???? bcd 二:变量扩充 除了shell中的meta,其它的[^a-zA-Z0-9_]几乎都可以作单词边界。同sed中关于单词边界[^a-zA-Z0-9_]的描述。 https://www.wendangku.net/doc/745023933.html,/forum/24/20040825/393964.html 这些功能有时候会在程序中有意想不到的作用! 例如: $ a=bcd $ echo ${a}.b bcd.b $ echo $a.php bcd.php $ echo $a%b bcd%b $ echo /$a/bc /bcd/bc 对于shell中的meta字符,则backslash。 $ echo $a\*b bcd*b 三:变量中的变量 $ a=bcd $ b=efg $ c=$a$b $ echo $c bcdefg $ d=$c.ghi $ echo $d

bcdefg.ghi 思考:若变量互相嵌套,会怎样呢? 四:变量的特异功能 到网中人的啦!(ps:重写真是没激情啊) file=/dir1/dir2/dir3/my.file.txt 我们可以用${ } 分别替换获得不同的值: ${file#*/}:从变量file的字符串左边开始,删除字符直到第一个“/”:dir1/dir2/dir3/my.file.txt ${file##*/}:从变量file的字符串左边开始,删除字符直到最后一个“/”:my.file.txt ${file#*.}:从变量file的字符串左边开始,删除字符直到第一个“.”:file.txt ${file##*.}:从变量file的字符串左边开始,删除字符直到最后一个“.”:txt 其实,在“#”后面,无非就是一个匹配问题,不限于两个,你可以放任意个字符,还可以用shell中另外的通配符“?”“[…]”“[!…]”,例如: $ echo ${file#????} 1/dir2/dir3/my.file.txt $ echo ${file#*[0-9]} /dir2/dir3/my.file.txt $ echo ${file#/dir1/dir[0-9]} /dir3/my.file.txt “#”:相当于最小匹配,遇到一个最小的符合其后表达式的字符串(单个或多个)即中止匹配动作; “##”:相当于最大匹配,它尽可能的匹配更多的字符。 我们可以拿“*”来说明: * 在shell中表示匹配任何符号包括空。当它在只有一个# 的变量替换中,受最小匹配的影响,它不会匹配任何可打印字符,只匹配一个空,也就是什么也不匹配,你完全可以忽略它的存在; 当在有两个## 的变量替换中,受最大匹配的影响,一个* 表示匹配整个字符串。 如果想匹配字符“*”时,要在“*”前加一个“\”,其后的“*”失去通配符的功能。 但是还有一种例外情况(请接着看) 例: $ file2=abcd.efgh.ijkl.oopp $ echo ${file2#*.*.*.*} $ echo ${file2##*.*.*.*} 想想上面两个的输出是什么? $ echo ${file2#*.*.*.*} oopp $ echo ${file2##*.*.*.*} 空 ??知道为什么吗?因为:“*”匹配任何符号包括空。遇到一个“#”时,最后一个“*”就匹配“空”去了。看下面的: $ echo ${file2#*.*.*.?} opp $ echo ${file2#*.*.*.?*} opp

Shell脚本编程详解-吐血共享

第12章 Shell 脚本编程 ● Shell 命令行的运行 ● 编写、修改权限和执行Shell 程序的步骤 ● 在Shell 程序中使用参数和变量 ● 表达式比较、循环结构语句和条件结构语句 ● 在Shell 程序中使用函数和调用其他Shell 程序 12-1 Shell 命令行书写规则 ◆ Shell 命令行的书写规则 对Shell 命令行基本功能的理解有助于编写更好的Shell 程序,在执行Shell 命令时多个命令可以在一个命令行上运行,但此时要使用分号(;)分隔命令,例如: [root@localhost root]# ls a* -l;free;df 长Shell 命令行可以使用反斜线字符(\)在命令行上扩充,例如: [root@localhost root]# echo “ this is \ >long command ” This is long command 注意: “>”符号是自动产生的,而不是输入的。 12-2 编写/修改权限及执行Shell 程序的步骤 ◆ 编写Shell 程序 ◆ 执行Shell 程序 Shell 程序有很多类似C 语言和其他程序设计语言的特征,但是又没有程序语言那样复杂。Shell 程序是指放在一个文件中的一系列Linux 命令和实用程序。在执行的时候,通过Linux 操作系统一个接一个地解释和执行每条命令。首先,来编写第一个Shell 程序,从中学习Shell 程序的编写、修改权限、执行过程。

12-2-1 编辑Shell程序 编辑一个内容如下的源程序,保存文件名为date,可将其存放在目录/bin下。 [root@localhost bin]#vi date #! /bin/sh echo “Mr.$USER,Today is:” echo &date “+%B%d%A” echo “Wish you a lucky day !” 注意: #! /bin/sh通知采用Bash解释。如果在echo语句中执行Shell命令date,则需要在date 命令前加符号“&”,其中%B%d%A为输入格式控制符。 12-2-2 建立可执行程序 编辑完该文件之后不能立即执行该文件,需给文件设置可执行程序权限。使用如下命令。[root@localhost bin]#chmod +x date 12-2-3 执行Shell程序 执行Shell程序有下面三种方法: 方法一: [root@localhost bin]#./ date Mr.root,Today is: 二月 06 星期二 Wish you a lucky day ! 方法二: 另一种执行date的方法就是把它作为一个参数传递给Shell命令: [root@localhost bin]# Bash date Mr.root,Today is: 二月 06 星期二 Wish you a lucky day ! 方法三: 为了在任何目录都可以编译和执行Shell所编写的程序,即把/bin的这个目录添加到整个环境变量中。 具体操作如下: [root@localhost root]#export PATH=/bin:$PATH [root@localhost bin]# date Mr.root,Today is: 二月 06 星期二 Wish you a lucky day !

Shell十三问-ChinaUnix精华贴整理

转自ChinaUnix 1) 为何叫做shell ? 在介绍shell 是甚么东西之前,不妨让我们重新查看用户与计算机系统的关系: 图(FIXME) 我们知道计算机的运作不能离开硬件,但用户却不能直接对硬件作驱动, 硬件的驱动只能通过一个称为"操作系统(Operating System)"的软件来控管, 事实上,我们每天所谈的linux ,严格来说只是一个操作系统,我们称之为"核心(kernel)"。 然而,从用户的角度来说,用户也没办法直接操作kernel , 而是通过kernel 的"外壳"程序,也就是所谓的shell ,来与kernel 沟通。 这也正是kernel 跟shell 的形像命名关系。如图: 图(FIXME) 从技术角度来说,shell 是一个用户与系统的交互界面(interface), 主要是让用户通过命令行(command line)来使用系统以完成工作。 因此,shell 的最简单的定义就是---命令解释器(Command Interpreter): * 将用户的命令翻译给核心处理, * 同时,将核心处理结果翻译给用户。 每次当我们完成系统登录(log in),我们就取得一个交互模式的shell ,也称为login shell 或primary shell。 若从进程(process)角度来说,我们在shell 所下达的命令,均是shell 所产生的子进程。这现像,我们暂可称之为fork 。 如果是执行脚本(shell script)的话,脚本中的命令则是由另外一个非交互模式的子shell (sub shell)来执行的。 也就是primary shell 产生sub shell 的进程,sub shell 再产生script 中所有命令的进程。 (关于进程,我们日后有机会再补充。) 这里,我们必须知道:kernel 与shell 是不同的两套软件,而且都是可以被替换的: * 不同的操作系统使用不同的kernel , * 而在同一个kernel 之上,也可使用不同的shell 。 在linux 的缺省系统中,通常都可以找到好几种不同的shell ,且通常会被列与如下文件里: /etc/shells 不同的shell 有著不同的功能,且也彼此各异、或说"大同小异"。 常见的shell 主要分为两大主流: sh: burne shell (sh) burne again shell (bash) csh: c shell (csh) tc shell (tcsh) korn shell (ksh) (FIXME) 大部份的Linux 系统的缺省shell 都是bash ,其原因大致如下两点: * 自由软件 * 功能强大 bash 是gnu project 最成功的产品之一,自推出以来深受广大Unix 用户喜爱, 且也逐渐成为不少组织的系统标准。 2) shell prompt(PS1) 与Carriage Return(CR) 的关系? 当你成功登录进一个文字界面之后,大部份情形下, 你会在荧幕上看到一个不断闪烁的方块或下划线(视不同版本而别), 我们称之为*光标*(cursor)。 光标的作用就是告诉你接下来你从键盘输入的按键所插入的位置, 且每输如一键光标便向右边移动一个格子,若连续输入太多的话,则自动接在下一行输入。

linux下的静态库与动态库的区别和使用

1.L inux动态库和静态库的区别 1.什么是库 在windows平台和linux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二者库的二进制是不兼容的。本文仅限于介绍linux下的库。 2.库的种类 linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。 静态库在程序编译时会被连接到目标代码中,目标程序运行时将不再需要该动态库,移植方便,体积较大,但是浪费空间和资源,因为所有相关的对象文件与牵涉到的库被链接合成一个可执行文件。 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入,因此体积较小,可以实现进程间的资源共享,甚至可以真正做到链接载入完全由程序员在程序代码中控制,另外将一些程序的升级变得简单,但是在程序运行时需要动态库存在。 3.库存在的意义 库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。 4.库文件是如何产生的在linux下 静态库的后缀是.a,它的产生分两步 Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表 Step 2.ar命令将很多.o转换成.a,成文静态库 例如:$gcc -c hello.c $ ar crs libmyhello.a hello.o 动态库的后缀是.so,它由gcc加特定参数编译产生。 例如:$gcc -c hello.c $ gcc -shared -fPIC -o libmyhello.so hello.o 参数解析:

c语言模拟shell命令行解释程序

北京联合大学 《操作系统课程设计》实验一:命令行解释程序 学院:信息学院专业:计算机科学与技术 课程:操作系统班级: 1 1 0 3 B 姓名:傅笔贵学号: 2009080305302 2014年7 月10 日

一.采用的数据结构说明 字符数组: 本程序中包含的字符数组有: filename1[20]:在Ccopy()函数中,存储源文件路径和名字的字符数组。 filename2[20]:在Ccopy()函数中,存储目标文件路径和名字的字符数组。 oldname[20]:在Cmv()函数中用来保存源文件路径和名字的字符数组。 newname[20]:在Cmv()函数中用来保存目标文件路径和名字的字符数组。 Cho2[6]:存取用户输入的指令,并用来作为Switch分支的判定条件之一。 File[20]:Cerase()函数中用来存放要删除的文件的路径和名字的字符数组。 Word[100]:在Cdis()中存放用户要回显的字符串。 二.源程序清单、注释和流程图 (1)流程图

(2)源程序和注释 #include #include #include #include #include #include #include int flag=1; char ch[8];//存储文件读取内容的中间变量 FILE *fp; FILE *fp1; char filename1[20];/*复制文件候存放的原文件名*/ char filename2[20];/*复制文件候存放的目标文件名*/ char oldname[20];/*用来存放移动文件的源文件名*/ char newname[20];/*用来存放移动文件的目标文件名*/ void start_copy(char *filename1,char *filename2) /*文件复制函数,可以实现文本和图片的复制*/ { if((fp=fopen(filename1,"rb"))==NULL||(fp1=fopen(filename2,"wb"))==NUL L) /*源文件或目标文件打开失败则无法进行复制*/ { printf("can't open the source file!\n"); exit(0); } else { fread(ch,1,8,fp);//一次读取八个字节的字节流,存放到ch字符数组里 while (!feof(fp))//没读取到文件尾部时,持续读取 { fwrite(ch,1,8,fp1);//写到目标文件里 fread(ch,1,8,fp);//继续读取 } fclose(fp);//关闭指针,释放内存 fclose(fp1); } }

linux操作系统之Shell编程

shell1.sh 显示日期和时间。 #!/bin/bash echo “current time is `date`” //date要加反引号 shell2.sh 显示文件名,并显示位置参数(执行时带一个参数)。(①$0是一个特殊的变量,它的内容是当前这个shell程序的文件名;②$1是一个位置参数,位置参数之间用空格分隔,shell取第一个位置参数替换程序文件中的$1,第二个替换$2,依次类推。) #!/bin/bash echo “the program name is $0” //$0是一个特殊的变数 echo “the first para is $1” //$1是一个位置参数 echo “the program exit” //执行时带一个参数如./shell2.sh abcd shell3.sh 判断并显示位置参数 #!/bin/bash if [ -d “$1”];then echo “$1 is directory ,existed” else echo “$1 does not exist ,now create it” mkdir $1 echo “$1 is created” fi //执行时带一个参数 shell4.sh 问候用户 #!/bin/bash user=`whoami` case $user in teacher) echo “hello teacher”;; root) echo “hello root”;; *) echo “hello $user,welcome” esac 1、求1+2+3+...+100的和是? #!/bin/bash

第六章 dc_shell综合脚本

第六章dc_shell命令解释程序 第一节设计目标 6-1-1背景介绍 dc_shell 是Synopsys Design Compiler的shell(命令解释程序),与unix的shell 类似。Unix的C shell 和Bourne-shell作为命令解释程序,在用户和unix 核之间实现了功能极强的接口程序。相同地,Dc_shell最为Synopsys Design Compiler的功能极强的命令解释程序。象unix shell 提供程序设计语言在unix 文件系统中操作一样,dc_shell 提供script(脚本)语言在Design Compiler 的设计中操作,且仿造unix shell 的相同的结构。 用dc_shell 脚本综合设计有许多优点:首先,脚本执行速度比象design analyzer 交互式的界面快得多,脚本也用来证明综合设计的过程。更重要的是,脚本提供一个重复编译的机制,这不仅对设计的再利用重要,而且对于当要求一项函数改变时,再次产生设计文件的所要求的时间最小化也很重要。 所有的这些优点源于使用脚本自动走完综合流程。但是,dc_shell 脚本能够做的远不只这些,它能扩展Design Analyzer和Design Compiler的功能。一些Design compiler命令的顺序由脚本得出。大多数经验丰富的Synopsys的用户将脚本和Design analyzer结合使用来分析和优化设计。 6-1-2 目标程序类型的审阅 dc_shell脚本生成设计目标程序和编译属性来引导综合流程。当编写dc_shell脚本时,考虑正在运行的目标程序/信息的类型是很重要的。这一节从“Design Compiler Family Reference Manual”的章节中总结了“design compiler”的概念。 6-1-2-1 实例、网络、端口 原理图由三个基础的构件组成:实例、网点、端口。实例是代表逻辑子程序或层次的符号,网络是代表在实例之间有电气连续性的导线,端口是用来代表层次连续性的线路终结器。这些都是标准的术语。使设计者感到新颖的是reference 的概念。 6-1-2-2 单元、引用、设计 如果一实例代表一逻辑子程序,则它能代表什么类型的子程序呢?一实例能代表一库元件或一设计。用许多术语描述设计是必须的因为一设计可能包含同一库元件(或子设计)的多重实例。 举例说,一典型设计包含与非门,设计中的每一门实例都被赋予唯一的单元名用来在非唯一的实例中彼此区分。同样的,一设计可能包含多个加法器,与与非门不同,加法器一般来说不是库元件,加法器是一个可逐步分解成库元件和网络且相互连接后执行加法器功能的完全设计。与库元件相同,每一子设计的实例都被赋予唯一的单元名。 库元件是无形的设计子程序且在设计中常被做为节点单元引用。设计是逻辑块,它们可作为独立的设计或作为更大设计的子设计。作为其它设计中连接上下关系的子模块,设计中每一个唯一的实例被作为一个分层次的单元引用。在一个单独设计的上下关系中,每一个实例具有唯一的单元名,这些单元引用库元件或设计。设计者可以对每个单元单独地进行优化,也可以通过布置属性或约束(在以下定义)对每个库元件或设计进行优化。但是,属性被直接加至库元件或设计中,这可能影响包含引用这些库元件或设计的每一个设计。 图6.1 单元、引用、设计之间的关系 假设你想要影响一个单独设计中的每一个与非门的优化而没有影响其它设计中的与非门则将会如何呢?引用的概念使这成为可能,设计中的每一个单元不仅是库元件中或设计中唯一命名的实例,而且是引用库元件或设计的一系列单元中的一员。 参考以下图6.2的设计: 图6.2脉动计数器:count_16 这个分层次设计的顶层是一个16位的计数器,顶层设计由与非门、或非门、8位计数器组成。在这层次设计的关系

shell程序设计

shell编程 教学要点 1.深入理解shell概念。 2.掌握linux下shell程序设计流程。 3.理解shell程序与C程序设计的区别。 4.掌握shell程序设计中用户变量和表达式的使用方法。一.Shell编程概述 问题1:请各位同学在home目录下创建5个目录,目录名称分别为student0,student1,student2,student3,student4.且修改它们的权限为所有用户都具有完全的操作权限。 问题2:请各位同学在home目录下创建100目录,目录名称为class1—class100. 解决办法:通过一个shell脚本程序来实现,程序如下,用vi编辑器建立一个firstshell文件,内容如下: #!/bin/bash //指明该程序被那个shell来执行! cd /home/shelldir //进入home/shelldir目录 mkdir newdir //在shelldir目录下新建newdir目录

i=0 //给变量i赋初值 while [ $i –lt 50 ]; do //循环,判断i是否小于50,成立继续循环 let i=i+1 //让i变量值增加1 mkdir /home/shelldir/newdir/student$i //在newdir目录下创建student1到student50 chmod 754 /home/shelldir/newdir/student$i done 保存文件,退出vi,通过执行#chmod a+x firstshell修改文件权限,赋予文件可执行权限,通过#./firstshell或者#/bin/bash firstshell来执行程序,查看程序运行结果。 程序说明: 1.程序必须以下面的行开始(必须方在文件的第一行): #!/bin/bash 符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/bash来执行程序。 2.当编辑好脚本时,如果要执行该脚本,还必须使其可执行。要使脚本可执行,必须为脚本添加可执行权限。

实验3_shell程序设计

实验三shell程序设计目的 1.理解shell操作环境 2.掌握shell程序编写方法 内容 1.练习、理解下面命令 history history 20 !! !vi alias alias ld=’ls -ld’ { date;pwd;tty;stty; } > file1 echo ”123*456+789” | bc var1=”abcd1234” echo ${var1:3:4} var2=${var1:=”abcd1200”} echo $var2 echo ”$HOME $PWD” echo ”我的主目录是$HOME” echo ”当前目录是$PWD” arr1=(long live chair mao) echo ${arr1[1]} arr2=(`date`) echo ${arr2[3]} echo ${arr1[*]} echo ${arr1[@]} echo $$ echo $? [ $? -eq 0 ] || echo ”上面命令执行失败。”

2.编写shell程序,按要求文件名保存在个人中目录下“实验3”子目录下。 1)文件名feb.sh,输出数列1 1 2 3 5 8 13 …前30项; 2)录入、阅读、运行程序dust.sh,理解程序的意义。dust.sh代码如下: #!/bin/bash If [ $# -eq 0 ] then echo ”指定一个文件名。” else gzip $1 #压缩文件 mv $1.gz $HOME/dustbin echo ”文件$1被删除!” fi exit 0 3)文件名colle.sh,收集2016 级学生实验3编写程序文件。学生用户的名称是学生学号,如2016012999,用户主目录是/home/学号(如/home/2016012999)。将学生用户主目录下“实验3”子目录中文件feb.sh(有些学生为有该文件,有些学生没有)复制用户主目录下,并改名为“学号_feb.sh”(如2016012999_feb.sh)。 3.阅读理解程序,程序文件在主机202.117.179.233,目录/var/materials下。 实验报告书写指导 1.将你对操作、显示信息的理解写在操作命令后; 2.实验报告提交到202.117.179.110; 3.编写的shell程序保存在个人目录下“实验3”子目录中。

个人整理shell脚本编程笔记

shell脚本编程学习笔记(一) 一、脚本格式 vim shell.sh #!/bin/bash//声明脚本解释器,这个‘#’号不是注释,其余是注释 #Program://程序内容说明 #History://时间和作者 二、shell变量的种类 用户自定义变量:由用户自己定义、修改和使用 与定义变量:Bash与定义的特殊变量,不能直接修改 位置变量:通过命令行给程序传递执行的参数 1、定义变量: 变量名要以英文字母或下划线开头,区分大小写。 格式:变量名=值 输出变量:echo $变量名 2、键盘输入为变量内容: 格式:read [-p "信息"] 变量名 如:read -p "pewase input your name:" name 3、不同引号对变量的作用 双引号"":可解析变量,$符号为变量前缀。 单引号'':不解析变量,$为普通字符。 反引号``:将命令执行的结果输出给变量。 三、shell条件测试 1、test命令: 用途:测试特定的表达式是否成立,当条件成立时,命令执行后的返回值为0,否则为其他数字。 格式:test 条件表达式[ 条件表达式] (注意:[]与表达式之间存在空格) 2、常见的测试类型: 测试文件状态 格式:[ 操作符文件或目录] 如:if [ -d /etc ] then echo "exists" else echo "not exists" fi 常见的测试操作符: -d:测试是否为目录 -e:测试目录或文件是否存在 -f:测试是否为文件 -r:测试当前用户是否有读权限 -w:测试当前用户是否有写权限 -x:测试当前用户是否有执行权限

实验一Shell程序设计已完成

Shell程序设计 一、实验目的 1、了解和熟悉创建并使用脚本的步骤。 2、熟悉bash的控制结构。 3、学会简单的shell编程。 二、实验内容 1、创建一个简单的列目录和日期的shell 脚本并运行之。 2、用Shell 语言编制Shell 程序,该程序在用户输入年、月之后,自动打印数出该年该月的日历。 3、编程提示用户输入两个单词,并将其读入,然后比较这两个单词,如果两个单词相同则显示“Match”,并显示“End of program”,如果不同则显示“End of program”。 4、编程使用case 结构创建一个简单的菜单,屏幕显示菜单: a. Current date and time b. User currently logged in c. Name of the working directory d. Contents of the working directory Enter a,b,c or d: 三、实验步骤 1、创建一个简单的列目录和日期的shell脚本并运行之。 步骤: 键入下列命令,创建一个新文件: (1)cat >new_script (2)输入下列行: echo Your files are ls echo today is date 按回车键将光标移到一个新行,按ctrl + D 键保存并退出。 (3)检查文件内容,确保它是正确的: #cat new_script (4)运行脚本,输入它的文件名: #new_script 该脚本不运行。 (5)输入下列命令,显示文件的权限: #ls -l new_script 权限表明该文件不是可执行。要通过简单调用文件名来运行脚本,必须有权限。 (6)输入下列命令,使new_script变成可执行文件。 chmod +x new_script (7)要查看新的权限,输入: ls-l 现在拥有文件的读、写和执行权限。 (8)输入新脚本的名字以执行它: new_script 所有输入到文件的命令都执行,并输出到屏幕上。

LinuShell程序设计实验

Linux shell程序设计实验指南 请在vi中逐一编辑并执行以下10个shell脚本程序,然后结合所学知识和程序的输出分析各程序中各语句的含义: 1.编写一个简单的回显用户名的shell程序。 #!/bin/bash #filename:date echo "Mr.$USER,Today is:" echo 'date' echo Whish you a lucky day! 2.使用if-then语句创建简单的shell程序。 #!/bin/bash #filename:bbbb echo -n "Do you want to continue: Y or N" read ANSWER if [ $ANSWER=N -o $ANSWER=n ] then exit fi 3.使用if-then-else语句创建一个根据输入的分数判断是否及格的shell程序。 #!/bin/bash #filename:ak echo -n "please input a score:" read SCORE echo "You input Score is $SCORE" if [ $SCORE -ge 60 ]; then echo -n "Congratulation!You Pass the examination." else echo -n "Sorry!You Fail the examination!" fi echo -n "press any key to continue!" read $GOOUT 4.使用case语句创建一个菜单选择的shell程序。 #!/bin/bash #filename:za #Display a menu echo _ echo "1 Restore"

题目1 shell 程序设计

题目1 shell 程序设计 1.1 实验目的 Linux操作系统中shell是用户与系统内核沟通的中介,它为用户使用操作系统的服务提供了一个命令界面。用户在shell提示符($或#)下输入的每一个命令都由shell先解释,然 后传给内核执行。本实验要求用C语言编写一个简单的shell程序,希望达到以下目的: ●用C语言编写清晰易读、设计优良的程序,并附有详细的文档。 ●熟悉使用Linux下的软件开发工具,例如gcc、gdb和make。 ●在编写系统应用程序时熟练使用man帮助手册。 ●学习使用POSIX/UNIX系统调用、对进程进行管理和完成进程之间的通 信,例如使用信号和管道进行进程间通信。 ●理解并发程序中的同步问题。 ●锻炼在团队成员之间的交流与合作能力。 1.2 实验要求 1.2.1 ysh解释程序的重要特征 本实验要实现一个简单的命令解释器,也就是Linux中的shell程序。实验程序起名为ysh,要求其设计类似于目前流行的shell解释程序,如bash、csh、tcsh,但不需要具备那么复杂的功能。ysh程序应当具有如下一些重要的特征: ●能够执行外部程序命令,命令可以带参数。.。 ●能够执行fg、bg、cd、history、exit等内部命令。 ●使用管道和输入输出重定向。 ●支持前后台作业,提供作业控制功能,包括打印作业的清单,改变当前 运行作业的前台/后台状态,以及控制作业的挂起、中止和继续运行。 除此之外,在这个实验中还须做到: ●使用make工具建立工程。 ●使用调试器gdb来调试程序。 ●提供清晰、详细的设计文档和解决方案。 1.2.2 ysh解释程序的具体要求 1. Shell程序形式 本实验的ysh程序设计不包括对配置文件和命令行参数的支持。如果实现为像bash那样支持配置文件,当然很好,但本实验并不要求。ysh应提供一个命令

shell程序设计(通信)1

Shell程序设计 本章的学习目标 ●了解shell的地位和作用 ●熟练掌握shell脚本的建立与执行方法 ●掌握shell的变量及特殊字符 ●掌握shell的输入输出命令 ●掌握shell程序逻辑结构语句 主要内容 ● Shell概述 ● Shell的变量 ● Shell中的特殊字符 ●Shell编辑中的输入输出命令 ● Shell结构控制语句 Shell简介 1、Shell的功能(1)作为命令解释程序 (2)作为一种高级程序设计语言 shell是一种命令行解释程序,它提供了用户与操作系统之间基于命令行的交互界面。用户命令行输入命令,由SHELL对它们做出解释,并将其送往操作系统去执行。然而,它不仅仅是一种交互式语言,它还是一种可编程的程序设计语言。将若干个shell命令写入一个文件就构成了一个shell程序,它可以被shell逐条的解释执行。 Shell简介 shell程序可以使用各种变量、参数和控制结构来组织命令流程,自动化的完成各种复杂冗繁的处理工作。 shell是基于字符串的语言:只做字符串处理,不支持复杂的数据结构和运算。Shell 输出也全部是字符方式。 2、Shell的主要版本:sh csh ksh 在linux系统中流行的使用的shell主流是Bash,它是Bourne Again Shell的缩写,bash 是由bourne shell发展而来的,但是它包含了csh和ksh的特性。 shell脚本的建立与执行 ●shell脚本的建立 ●Shell脚本是文本文件,可以用任何文本编辑器建立和编辑脚本,shell脚本文件 的名称没有限定的扩展名,通常不带扩展名或带“.sh”扩展名。 ●①vi shell脚本名 ●②cat >文件名 ●。。。。。 Ctrl+d 例9.1 第1个Shell程序: $ cat hello #hello程序 # This is a shell script to say hello. echo Hello World! echo -n “Today is ” date “+%A, %B %d, %Y.” $ . hello #运行hello程序 Hello World!

linux Shell(脚本)编程入门 实例讲解详解

linux Shell(脚本)编程入门实例讲解详解 为什么要进行shell编程 在Linux系统中,虽然有各种各样的图形化接口工具,但是sell仍然是一个非常灵活的工具。Shell不仅仅是命令的收集,而且是一门非常棒的编程语言。您可以通过使用shell使大量的任务自动化,shell特别擅长系统管理任务,尤其适合那些易用性、可维护性和便携性比效率更重要的任务。 下面,让我们一起来看看shell是如何工作的: 建立一个脚本 Linux中有好多中不同的shell,但是通常我们使用bash (bourne again shell) 进行shell编程,因为bash是免费的并且很容易使用。所以在本文中笔者所提供的脚本都是使用bash(但是在大多数情况下,这些脚本同样可以在bash 的大姐,bourne shell中运行)。 如同其他语言一样,通过我们使用任意一种文字编辑器,比如nedit、kedit、emacs、vi等来编写我们的shell程序。程序必须以下面的行开始(必须方在文件的第一行): 符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。当编辑好脚本时,如果要执行该脚本,还必须使其可执行。 要使脚本可执行: 然后,您可以通过输入: ./filename 来执行您的脚本。 注释 在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。 变量 在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:

相关文档