shell学习笔记.docx

上传人:b****3 文档编号:4982590 上传时间:2022-12-12 格式:DOCX 页数:33 大小:48.36KB
下载 相关 举报
shell学习笔记.docx_第1页
第1页 / 共33页
shell学习笔记.docx_第2页
第2页 / 共33页
shell学习笔记.docx_第3页
第3页 / 共33页
shell学习笔记.docx_第4页
第4页 / 共33页
shell学习笔记.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

shell学习笔记.docx

《shell学习笔记.docx》由会员分享,可在线阅读,更多相关《shell学习笔记.docx(33页珍藏版)》请在冰豆网上搜索。

shell学习笔记.docx

shell学习笔记

Shell学习笔记

Shell语法

变量:

在Shell中,我们在使用变量之前并不需要进行声明.相反我们可以在需要的时候进行简单的使用就可以了.在默认的情况下,所有的变量都是作为字符串进行存储的,虽然有时我们会用数字为其赋值.Shell以及其他的一些实用的转换程序会将数字字符串转换成相应的值为进行操作.在Linux系统中是要区分大小的,所以在Shell看来变量foo与Foo是不同的.

在Shell中我们要访问变量的值,我们要在变量前加上一个$.当我们要为变量赋值时,我们可以只使用变量的名字,Shell会在需要的时候进行动态创建.检测变量内容一个简单的办法就是在终端进行输出,这时要在变量前加上一个$.

在命令行中我们可以用下面的方法来设置和检测变量的值:

$salutation=Hello

$echo$salutation

Hello

$salutation=”YesDear”

$echo$salutation

YesDear

$salutation=7+5

$echo$salutation

7+5

我们还可使用read命令将用户的输入赋值给变量.这样就会将变量的名字作为参数并会等待用户的输入.read命令会在用户输入回车的时候结束.当从终端读入变量时我们并不需要使用引号.如下面的例子:

$readsalutation

Wiegeht’s?

$echo$salutation

Wiegeht’s?

引号:

在继续我们的学习之前我们要清楚引号的作用.

通常脚本中的参数是由空白字符来分隔的,如空格,Tab或是回车.如果我们要我们的参数包含一个或是更多个参数,我们就要使用引号了.

例如变量$foo的行为要看我们使用的引号的类型了.如果我们是用双引号,在这一行执行时就会用他的值进行替换,而如果我们使用单引号就不会发生这样的替换.我们还可以使用转义字符\来除去$的特殊意义.

在通常的情况下,我们双引号来包含字符串,这样就可以防止变量被空白符所分隔,而且会用变量的值进行替换.

在下面的这个例子中我们就会看到引号对于变量输出的影响:

#!

/bin/bash

myvar=”Hithere”

echo$myvar

echo“$myvar”

echo‘$myvar’

echo\$myvar

echoEntersometext

readmyvar

echo‘$myvar’nowequals$myvar

exit0

这个程序的输出为:

Hithere

Hithere

$myvar

$myvar

Entersometext

HelloWorld

$myvarnowequalsHelloWorld

工作原理

我们创建了变理myvar,并赋值为Hithere.变量的内容由命令echo显示出来,从而可以看出$字符扩展对变量内容的影响.从这输出我们可以看出双引号并不会影响变量的替换,而单引号和反斜线却会有这样的影响.我们同时使用一个read命令来从用户得到输入.

环境变量

当启动一个Shell脚本时,一些变量会由环境中的值进行初始化.在脚本中这些变量通常为大写字母,从而与用户定义的变量进行区分,而用户定义的变理常用小写字母来表示.创建的变量依赖于我们个人的配置.其中的许多列在手册页中,但是基本的一些列在下面的表中:

$HOME   当前用户的主目录

$PATH   用来进行命令查找的由冒号分隔的目录列表

$PS1   命令提示,通常为$,但是在bash中我们可以使用更为复杂的值.例如,字符串[\u@\h\W]$是流行的默认用法来告诉我们当前的用户,机器名称以及当前的工作目录,同时给出$提示.

$PS2   第二提示符,当提示额外的输入时使用,通常为>

$IFS   输入区域分隔符.当Shell读入输入时会使用一个字符列表来分隔输入的单词,通常是空格,tab和新行字符.

$0   Shell脚本的名称.

$#   传递的参数个数.

$$   脚本的进程ID,通常用在一个脚本内部用来建立唯一的一个临时文件,如/tmp/tmp-file_$$.

如果我们的脚本调用一些参数,那么会建立一些其他的变量.即使没有传递参数,环境变量$#仍然存在,但是值却为0.

参数变量列在下面这个表中:

$1,$2,...   传递给脚本的参数.

$*   以单变量的形式显示所有的参数列表,由环境变量IFS中的第一个字符分隔.

$@   $*的一个灵巧变形.他并不使用IFS环境变量,所以如果IFS为空那么所有的所有的参数会一起运行.

我们可以通过下面的测试容易的看出$@和$*的区别:

$IFS=’’

$setfoobarbam

$echo“$@”

foobarbam

$echo“$*”

foobarbam

$unsetIFS

$echo“$*”

foobarbam

正如我们所看到的,在双引号内,$@将参数进行分隔显示,而与IFS的值无关.通常来说,如果我们要访问参数,$@是一个很灵敏的选择.

我们不仅可以用echo命令打印出变量的内容,而且我们可以使用read命令来读取他们的内容.

参数和环境变量

下面的脚本展示了简单变量的处理.在我们输入了下面的脚本内容并保存为try_var,我们一定要记得用命令chmod+xtry_var为其加上可执行权限.

#!

/bin/sh

salutation=”Hello”

echo$salutation

echo“Theprogram$0isnowrunning”

echo“Thesecondparameterwas$2”

echo“Thefirstparameterwas$1”

echo“Theparameterlistwas$*”

echo“Theuser’shomedirectoryis$HOME”

echo“Pleaseenteranewgreeting”

readsalutation

echo$salutation

echo“Thescriptisnowcomplete”

exit0

如果我们运行这个脚本我们会得到下面的输出:

~$./try_var.shfoobarbaz

Hello

Theprogram./try_var.shisnowrunning

Thesecondparameterwasbar

Thefirstparameterlistwasfoobarbaz

Theuser'shomedirectoryis/home/mylxiaoyi

Pleaseenteranewgreeting

hello

Thescriptisnowcomplete

工作原理:

这个脚本创建了一个名为salutation的变量并显示他的内空,然后显示了各种参数变量,而环境变量$HOME已经存在并且已经有适当的值.

函数:

所有程序语言的基本原则是测试条件并在这些测试的基础上进行各种不同的操作.在我们讨论这个话题之前,我们先来看一下在Shell脚本中我们会用到的函数构造以及我们要使用的控制结构.

一个Shell脚本可以测试由命令行调用的任何命令的返回代码,包括我们自己书写的脚本.这就是我们在每一个Shell脚本最后包含exit代码的重要原因.

test或[命令:

事实上,大多数的脚本大量的使用了Shell真假检测的test或是[命令.在大多数的系统上,[和test命令是同义的,但是当使用了一个[命令时而同时为了可读在末尾使用了一个]命令.使用[命令看起来有一点奇怪,但是这个命令在代码中会使得命令的语法看起来要简单,整洁,并且与其他的程序语言很相像.

ls-l/usr/bin/[

-rwxr-xr-x1rootroot250402005-11-1621:

17/usr/bin/[

我们会使用一个简单的测试例子来介绍test命令:

检测一个文件是否存在.用于这个目的的命令是test-f,所以我们可以用下面的脚本:

iftest-ffred.c

then

...

fi

我们也可以像下面的样子来写:

if[-ffred.c]

then

...

fi

test命令的返回代码(条件是否满足)决定于条件代码是否运行.

在这里我们要注意是我们必须在[和条件之间用空格进行分隔.我们可以用下面的方法来记住这一点:

[是test命令的另一种写法,而我们要在test命令后输入空格.

如果我们喜欢将then与if放在同一行,我们必须要加一个冒号来与then进行分隔:

if[-ffred.c];then

...

fi

我们可以用的test命令的条件类型有以下的三种:

字符串比较,算术比较和文件条件.下面的三张表展示了这些条件类型:

字符串比较:

string1=string2   如果相等则为真

string1!

=string2   如果不等则为真

-nstring      如果不空则为真

-zstring      如果为空则为真

算术比较:

expression1-eqexpression2   如果相等则为真

expression1-neexpression2   如果不等则为真

expression1-gtexpression2   如果大于则为真

expression1-ge   expression2   大于等于则为真

expression1-ltexpression2   如果小于则为真

expression1-leexpression2   小于等于则为真

!

expression         如查为假则为真

文件:

-dfile      如果为目录则为真

-efile      如果存在则为真(在这里要注意的是,由于历史原因,-e选项并不可移植,所以常用的是-f选项

-ffile      如果为常规文件则为真

-gfile      如果设置了组ID则为真

-rfile      如果文件可读则为真

-sfile      如果文件大小不为零则为真

-ufile      如果设置了用户ID则为真

-wfile      如果文件可写则为真

-xfile      如果文件可执行则为真

现在我们似乎走得有一点的太前了,但是接下来的是一个例子.在这里我们要测试文件/usr/bash,这样我们就可以清楚的看到这些条件的用法:

#!

/bin/sh

if[-f/bin/bash]

then

  echo“file/bin/bashexists”

fi

if[-d/bin/bash]

then

  echo“/bin/bashisadirectory”

else

  echo“/bin/bashisNOTadirectory”

fi

在测试为真以前,所有的文件测试条件要法度文件存在.这个列表包含了test命令常用的选项,所以我们可查看手册页得到一个完全的信息.如果我们正在使用bash,而其中内嵌了test,我们可以用命令helptest得到详细的信息.

 

控制结构

Shell有一结构控制集合,我们再一次说明他们与其他的程序语言非常相像.

If

if语句是相当简单的:

他测试一个命令的结果,并且有选择的执行一组语句:

ifcondition

then

  statements

else

  statements

fi

使用if命令:

下面的这个例子中显示if的普通用法,他会询问一个问题并依据这个问题来进行回答:

#!

/bin/sh

echo“Isitmorning?

Pleaseansweryesorno”

readtimeofday

if[$timeofday=“yes”];then

  echo“Goodmorning”

else

  echo“Goodafternoon”

fi

exit0

这会产生下面的输出:

$./if.sh

Isismorning?

pleaseansweryesorno

yes

Goodmorning

这个脚本使用[命令来测试变量timeofday的值.这个结果会被if命令来使用,从而会执行不同的程序代码.

elif

但是不是幸的是,对于这个简单的脚本却有着许多的问题.他会将yes以外的任何答案理解为no.为了防止这样的问题出现我们可以使用elif结构,这样就会允许我们在if执行else部分时添加第二个条件.

我们可以修改上面的脚本以使用当用户输入yes或no以外的内容时报告错误信息.我们的做法是用elif来代替else从而添加另一个条件.

#!

/bin/sh

echo“Isitmorning?

Pleaseansweryesorno”

readtimeofday

if[$timeofday=“yes”]

then

  echo“Goodmorning”

elif[ $timeofday=“no”];then

  echo“Goodafternoon”

else

  echo“Sorry,$timeofdaynotrecognized.Enteryesorno”

  exit1

fi

exit0

工作原理:

这与上一个例子较为相似,但是在这一次如果if的测试条件不为真则使用elif命令测试变量的值.如果这些没有一个成功,则会打印出一条错误信息并且脚本退出并返回代码1,而返回值则可以用作另一个调用此脚本的程序查看脚本是否成功.

变量的问题:

现在修正了一个最明显的问题,但是却潜伏着另一个更细小的问题.我们可以试一下这个新脚本,但是我们仅是输入回车(或是其他的内容)而不回答这个问题,我们就会得到下面的错误信息:

[:

=:

unaryoperatorexpected

出了什么样的错误呢?

问题就在于第一个if语句,当这个变量timeofday进行了测试,他包含一个空串.所以这样if语句看起来就是下面的样子:

if[=“yes”]

而这并不是一个可用的条件.为了避免这样的问题,我们可以用双引号将变量括起来:

if[“$timeofday”=“yes”]

当传递一个空变量给这个测试时:

if[“”=“yes”]

我们的新脚本如下:

#!

/bin/sh

echo“Isitmorning?

Pleaseansweryesorno”

readtimeofday

if[“$timeofday”=“yes”]

then

  echo“Goodmorning”

elif[“$timeofday”=“no”];then

  echo“Goodafternoon”

else

  echo“Sorry,$timeofdaynotrecognized.Enteryesorno”

  exit1

fi

exit0

这样对于只是回车的答案来说就是一个安全的脚本了.

for

我们用for结构在任何字符串的集合的值范围内进行循环.他们可以简单的列在程序中,或是更为一般的,可以是文件名的Shell扩展结果.

语法如下:

forvariableinvalues

do

  statements

done

在下面的这个例子中,值为普通的字符,所以我们的脚本如下:

#!

/bin/sh

forfooinbarfud43

do

  echo$foo

done

exit0

我们会得到下面的结果:

./for.sh

bar

fud

43

工作原理:

这个例子创建了一个变量foo,并且在for循环中每次赋于一个不同的值.因为Shell在默认的情况下认为所有的变量都包含字符串,所以在例子中就会像使用字符串fud一样的来使用43.

使用通配符

正如我们在前面的那样,通常情况下我们会在for循环中使用文件名的Shell扩展.我们这样说的意思是在字符串值中使用通配符,并且使得Shell在运行时填充所有的值.

我们已经在我们最初的例子中看到这个例子.这个脚本使用了Shell扩展,*扩展成为当前目录下的所有文件名.这些中的每一个在for循环中轮流用作变量$i的值.

下面我们看一下另一个通配符的例子.想像一下如果我们要打印所有当前的目录下文件名中含有f字符的文件,而且我们知道我们所有的脚本以.sh结尾.我们可以用下面的脚本来完成我们的工作

#!

/bin/sh

forfilein$(lsf*.sh);do

 lpr$file

done

exit0

工作原理:

这里我们展示了$(command)的语法.基本来说,for命令所使用的参数列表是由包含在$()中的命令的输出来提供的.这个脚本将f*.sh扩展成所有与这个模式匹配的内容.

while

因为在默认的情况下认为Shell值为字符串,因而for循环对于在一系列的字符间进行循环是一个不错的选择,但是对于处理确定次数的循环命令来说就显得有一些笨拙了.

下面这个例了向我们展示了当我们用for循环来在20个数之间进行循环是一件多么麻烦的事情:

#!

/bin/sh

forfooin1234567891011121314151617181920

do

  echo“herewegoagain”

done

exit0

即使是我们使用通配符进行扩展,我们有时也会遇到不能确定我们所需要的循环次数.在这样的情况下,我们可以使用while循环,其语法格式如下:

whileconditiondo

 statements

done

如下面的一个进行密码检测的例子:

#!

/bin/sh

echo“Enterpassword”

readtrythis

while[“$trythis”!

=“secret”];do

 echo“Sorry,tryagain”

 readtrythis

done

exit0

其输出结果如下:

Enterpassword

password

Sorry,tryagain

secret

$

事实上这并不是安全的检测密码的方法,但是却可以很好的展示了while语句的用法.在do和done之间的语句将会被连续执行直到我们的测试条件不再为真为止.在我们的输出例子中我们检测到trythis的值与secret并不相等,循环将会继续直到$trythis与secret相等为止.然后我们就会执行done后的语句.

将while语句与算术运算进行组合我们就可以执行确定次数的循环操作.这要比我们刚才所看到的for的例子要简单得多.

#!

/bin/sh

foo=1

while[“$foo”-le20]

do

  echo“Herewegoagain”

  foo=$(($foo+1))

done

exit0

工作原理:

这个脚本使用[命令来检测foo的值并与20进行对比,如果小于或是等于则要执行循环体.在这个while循环中,(($foo+1))语法用来执行花括号内的算术运算,所以foo的值会在每一个循环后增加1.

因为foo不可以是一个空串,所以我们在在测试他的值时不需要用双引号来保护.我们这样做是因为这是一个好习惯.

until

until语句语法格式如下:

untilcondition

do

  statements

done

这与while循环十分相似,所不同的只是测试条件的相反.换句说,until是循环继续直到条件为真,而不是while的条件为真时才进行循环.

until语句适用于我们希望进行循环直到某件事发生时为止的情况.作为一个例子,我们可以考虑下面的情况:

当我们在命令行中输入另一个用户名进行登陆时发出响铃.

#!

/bin/sh

untilwho|grep“$1”>/dev/null

do

  sleep60

done

#nowringthebellandannouncetheexpecteduser.

echo-e\\a

echo“****$1hasjustloggedin****”

exit0

下面我们要说是case结构.case结构比起我们已经讨论这些内容来说要显得有一些复杂.他的语法如下:

casevariablein

 pattern[|pattern]...)statements;;

 pattern[|pattern]...)statements;;

 ...

esac

这种结构看起来有一些吓人,但是case结构却可以使得我们用一种诡异的方法来匹配变量的内容并且会依据所匹配的模式执行不同的语句.

在这里我们要注意第一个模式行是用双分号来分隔的.我们可以在第一个不同的模式之间放置多条不同的语句,所以我们需要使用双分号来标记一个模式的结束和另一个模式的开始.

case结构匹配多个模式并执行多个不同的相关的语句的能力使得这种结构可以很好的来处理用户的输入.展示case工作原理的最好的方法就是一个实际的例子.如下面的一个例子:

现在我们可以写一个新的处理用户输入的脚本版本,现在我们使用case结构,这样可以使得他更具选择并且可以处理不可辨识的输入.

#!

/bin/sh

echo“Isitmorning?

Pleaseansweryesorno”

readtimeofday

case“$timeofday”in

   yes)echo“GoodMorning”;;

   no)echo“GoodAfternoon”;;

   y)echo“GoodMorning”;;

   n)echo“GoodAfternoon”;;

   *)echo“Sorry,answernotrecognized”;;

esac

exit0

工作原理:

在这个脚本中,我们在每一种情况的输入中使用了多个字符串,这样case就会为每一个可能的语句检测一些不同的字符串.这样就会使得我们的脚本更为短小,而且实际的来说也更为易读.我们同时展示了*通配符的用法,即使这也许会匹配不希望的情况.例如,如果用户输入了never,这样就会匹配n*并且会显示Goodafternoon,而这并不是我们所希望的行为.在这里我们要注意如果*通配符使用了引号就不会起作用了.

最后,如果我们要使得这个脚本可以重用,但使用最后一个匹配模式时我们需要一个不同的返回值.在这里我们同时也加入set结构.

#!

/bin/sh

echo“Isitmorning?

Pleaseansweryesorno”

readtimeofday

ca

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1