Shell变量,判断和控制语句详解

来源:互联网 发布:淘宝线上活动 编辑:程序博客网 时间:2024/05/06 04:08

1. 变量与算术

POSIX Shell 为内嵌(inline) 算术提供T 一种标记法,称为算术展开(arithmetic expansion) 。Shell 会对$((…)) 里的算术表达式进行计算,再将计算后的结果放回到命令的文本内容。

1.1. 变量与环境

有两个相似的命令提供变量的管理,一个是readonly ,它可以使变量成为只读模式; 而赋值给它们是被禁止的。一个是export ,将变量放进环境中。

1.1.1 . export, readonly 命令

语法

export name[=word] …

export -p

readonly name[=word]…

readonly -p

用途

    export 用于修改或打印环境变童,readonly 则使得变量不得修改。

主要选项

    -p 打印命令的名称以及所有被导出( 只读) 变量的名称与值,这种方式可使

      得Shell 重新读取输出以便重新建立环境( 只读设置) 。

例如:

[root@local~]#hours_per_day=24 # 赋值

[root@local~]#readonly hours_per_day  # 设为只读模式

[root@local~]# PATH=$PATH:/usr/local/bin # 更新PATH

[root@local~]#export PATH    # 导出它

[root@local~]#export –p  # 显示当前的环境

export CDPATH=":/home/tolstoy"

export DISPLAY=":0.0"

export ENV="/home/tolstoy/.kshrc"

export EXINIT="set ai sm"

export FCEDIT="vi”

1.1.2 .env 命令

语法

env [-i 」[var=value …][command_name[arguments …]]

用途

    当command_name 被env 执行时,可针时被command_name 继承而来的环境

    有更细致的控制。

主要选项

     -i 忽略继承的环境,仅使用命令行上所给定的变量与值。

例如:

Env 临时改变变量

[root@local~]#env -i PATH=$PATH HOME=$HOME

#-i 选项是用来初始化(initializes) 环境变量的,也就是丢弃任何的继承值,仅传递命令行上指定的变量给程序使用。

1.1.3 . unset 命令

语法

unset[-v 」variable

unset -f function

用途

    从当前Shell 删除变量与函数。

主要选项

    -f 解除( 删除) 指定的函数。

-v 解除( 删除) 指定的变量。没有任何选项时,这是默认行为模式。

例如:

unset 命令解除变量设置

[root@local~]#unset full_name

[root@local~]#unset -v first middle last

使用unset -f 删除函数

[root@local~]#

who_is_on(){

who I awk ‘{print $1 }’| sort –u

}

unset -f who_is_on

2. 参数展开

参数展开(parameter expansion) 是Shell 提供变量值在程序中使用的过程。最简单的形式如下所示:

reminder="Time to go tv the dentist!” # 将值存储在reminder 中

sleep 120                              # 等待两分钟

echo $reminder                          # 显示信息

在Shell 下,有更复杂的形式可用于更特殊的情况。这些形式都是将变量名称括在花括号里(${variable}}, 然后再增加额外的语法以告诉3he11 该做些什么。如下:

reminder="Time to go to the dentist!“

sleep 120

echo _$(reminder)_

2.1. 展开运算符

表 1 :替换运算符

运算符

替换

${varname:-word}

如果 varname 存在且非 null ,则返回其值;否则,返回word,

用途 : 如果变量未定义,则返回默认值。

范例 : 如果 count 未定义,则 ${count:-0} 的值为 0 。

 

${varname:=word}

如果 varname 存在且不是 null ,则返回它的值 ; 否则,设置它为 word ,并返回其值。

用途 : 如果变量未定义,则设置变量为默认值。 .

范例 : 如果 count 未被定义,则 ${count:=0} 设置 count 为0 。

${varname:?message}

如果 varname 存在且非 null ,则返回它的值 ; 否则,显示varname:message ,并退出当前的命令或脚本。省略message 会出现默认信息 parameter null or not set 。注意,在交互式 Shell 下不需要退出。

用途 : 为了捕捉由于变量未定义所导致的错误。

范例 :${count:?"undefined"} 将显示 count: undefined! ,且如果 count 未定义,则退出。

${varname:+word}

如果 varname 存在且非 null ,则返回 word; 否则,返回 null。

用途 :. 为测试变量的存在。

范例 : 如果 count 已定义,则 ${count:+1} 返回 1( 也就是“真” ) 。

注意:表 1 里每个运算符内的冒号 (:) 都是可选的。如果省略冒号,则将每个定义中的“存在且非 null ”部分改为“存在”,也就是说,运算符仅用于测试变量是否存在。

表 2 :替换运算符

运算符

替换

${variable#pattern}

如果模式匹配于变量值的开头处,则删除匹配的最短部分,并返回剩下的部分。

例如: ${path#/*/}

结果: tolstoy/mem/long.file.name

${variable##pattern}

如果模式匹配于变量值的开头处,则删除匹配的最长部分,并返回剩下的部分。

例如: ${path##/*/}

结果: long.file.name

${variable%pattern}

如果模式匹配于变量值的结尾处,则删除匹配的最短部分,并返回剩下的部分。

例如: ${path%.*}

结果: /home/tolstoy/mem/long.file

${variable%%pattern}

如果模式匹配于变量值的结尾处,则删除匹配的最长部分,并返回剩下的部分。

例如: ${path%%.*}

结果: /home/tolstoy/mem/long

注:假设变量 path 的值为 /home/tolstoy/mem/long.file.name 。

2.2. 位置参数

所谓位置参数(positional parameter) ,指的是Shell 脚本的命令行参数(argument); 同时也表示在Shell 函数内的函数参数。它们的名称是以单个的整数来命名。出于历史的

原因,当这个整数大于9 时,就应该以花括号({}) 括起来:

echo first arg is $1

echo tenth arg is is${10}

下面介绍的特殊“变量”提供了对传递的参数的总数的访问,以及一次对所有参数的访问:

$#

提供传递到She11 脚本或函数的参数总数。举例如下:

while [$#'!= 0 ]        # 以shift 逐渐减少$# ,循环将会终止

do

        case $1 in $*

        。。。            # 处理第一个参数

esac

shift           # 移开第一个参数

done

shift

$*,$@

一次表示所有的命令行参数。这两个参数可用来把命令行参数传递给脚本或函数所

执行的程序。

$*”

将所有命令行参数视为单个字符串。等同于”$1  $2. ,. " 。 $IFS 的第一个字符用来作为分隔字符,以分隔不同的值来建立字符串。举例如下:

printf "The arguments were %s/n". ,“$*”

$@

“将所有命令行参数视为单独的个体,也就是单独字符串。等同于,"$1” ,”$2”… 。这是将参数传递给其他程序的最佳方式,因为它会保留所有内嵌在每个参数里的任何空白。举例如下:

lpr "$@"       # 显示每一个文件

2.3. 算术展开

表fi-4; 算术运算数

运算符

意义

顺序

++ --

增加及减少,可前置也可放在结尾

由左至右

+ - ! ~

一元(unary) 的正号与负号; 逻辑与位的(bitwise) 取反

由右至左

* / %

乘法、除法,与余数

由左至右

+ -

加法,减法

由左至右

<< >>

向左移位、向右移位

由左至右

< <= > >=

比较

由左至右

== !=

相等与不等

由左至右

&

位的AND

由左至右

^

位的Exclusive OR

由左至右

|

位的OR

由左至右

&& ||

逻辑AND 和OR

由左至右

?:

条件表达式

由右至左

= += -= 等

赋值运算

由右至左

 

可利用圆括号将子表达式语句块括起来。例如:

$((3>2)) 的值为 1

$(((3>2) || ((4<=1))) 也为 1

[root@local~]#i=5

[root@local~]# echo $((i++))  $i

5 6

[root@local~]# echo $((++i))  $i

7 7

3. 退出状态

每一条命令,不管是内置的、 Shell 函数,还是外部的,当它退出时,都会返回一个小的整数值给引用它的程序,这就是大家所熟知的程序的退出状态 (exit status) 。

3.1. exit 命令

语法

      exit [exit-value]

用途

    目的是从 Shell 脚本返回一个退出状态给脚本的调用者 .

主要选项

      无

3.2. 退出状态值

表 5: POSIX 的结束状态

意义

0

命令成功地退出

>0

在重定向或单词展开期间 (~ ,变量,命令,算术展开,以及单词切割 ) 失败

1-125

命令不成功地退出。特定的退出值的含义,是由各个单独的命令定义的

126

命令找到了,但文件无法执行

127

命令找不到

>128

命令因收到信号而死亡

3.3. 逻辑的NOT ,AND 与OR

示例 1:

if ! grep pattern myfile > /dev/null

then

       …# 模式不在这里

fi

示例 2:

if grep patternl myfile && grep pattern2 myfile

then

…#myfile 包含两种模式

Fi

示例 3:

if grep patternl myfile || grep pattern2 myfile

then

…#myfile 一个或另一个模式出现

fi

注意:这两种都是快捷(short-circuit) 运算符,即当判断出整个语句块的真伪时,Shell 会立即停止执行命令。举例来说,在commandl&&command2 下,如果commandl 失败,则整个结果不可能为真,所以command2 也不会被执行,以此类推,commandl || command2 指的就是: 如果commandl 成功,那么也没有理由执行command2 。

3.4. test 命令

test 命令有另一种形式 :[…] ,这种用法的作用完全与 test 命令一样。因此,下面

是测试两个字符串是否相等的两个语句 :

if test "$strl”= ”$str2”

then

       …

fi

第二种:

if  [  “$strl ” = “ $str2” ]

then

              …

Fi

 

表6 : test 表达式

运算符

如果… 一则为真

string

string 不是null

-b file

file 是块设备文件

-c file

file 是字符设备文件

-d file

file 是目录

-e file

file 存在

-f file

file 为一般文件

-g file

file 有设置它的setgid 位

-h file

file 是一符号链接

-L file

file 是一符号链接( 等同于-h)

-n string

string 是非空

-p file

file 是命令管道文件

-r file

file 是可读的

-S file

file 是socket

-s file

file 不是空的

-t n

文件描述符指向一终端

-u file

File 有设置它的setuid 位

-w file

File 是可写入的

-x file

File 是可执行的

-z string

字符串为null

s1 = s2

字符串1 与字符串2 相同

s1 != s2

字符串1 与字符串2 不同

n1 –eq n2

整数1 等于整数2

n1 –ne n2

整数1 不等于整数2

n1 –lt n2

整数1 小于整数2

n1 –gt n2

整数1 大于整数2

n1 –le n2

整数1 小于或等于整数2

n1 –ge n2

整数1 大于或等于整数2

 

4. 控制结构

4.1. if-elif-else-fi 语句

一般语法如下 :

If pipeline

    [pipeline…]

then

    statements-if-ture-1

[elif pipeline

    [pipeline … ]

then

    statements-if-true-2

  …]

[else

    statements-if-all-else-fails]

fi

4.2. ca se 语句

一般语法如下 :

case $1 in

-f)

…# 针对-f 选项的程序代码

;;

-d|-directory) # 尤许长选项

… 针对-d 选项的程序代码

;;

*)

echo $1:unknown option

exit 1

;;# 在"esac" 之前的;; 形式是一个好习惯,不过这里并非必要

esac

4.3. for 语句

第一种语法如下 :

for var in con1 con2 con3

do

    程序段

done

解释如下:

第一次循环时,$var 的内容为con1

第一次循环时,$var 的内容为con2

第一次循环时,$var 的内容为con3

。。。

第二种语法如下 :

for (( 初始值; 限制值; 执行步长))

do

    程序段

done

例如:

s=0

for((i=0;i<100;i++))

do

    s=s$(($s+$i))

done

echo “the result of ‘1+2+3+…+100’is $s”

4.4. while 与until 语句

第一种语法如下 :

while condition

do

statements

done

第二种语法如下 :

until condition

do

statements

done

5. 函数

就像其他的程序语言一样,函数 (function) 是指一段单独的程序代码,定义完整的单项工作。函数在使用之前必须先定义。这可通过在脚本的起始处,或是将它们放在另一个独立件里且以点号 (.) 命令来取用 (source) 它们。

定义方式如下所示。

#wait_for_user--- 等待用户登录

#wait_for_user user [sleeptime]

wait_for_user

      until who grep "$1”>/dev/null

      do

         sleep {$2:-30}

      done

}

使用Shell 的函数架构取代test 所执行的两个字符串的比较:

# equal- 一比较两个字符串

equal(){

      case "$1" in

      $2) # 两字符串匹配

return 0

;;

      esac

      return 1# 不匹配

}

if equal “$a””$b”…

 

在Shell 函数里,return 命令的功能与工作方式都与exit 相同

answer_the_question()

{

return 42

}

调用如下

x=$(answer_the_question, $@)

6. Shell 的追踪与调试

[root@local~]#sh [-nvx] scripts.sh

参数:

-n: 不要执行脚本,仅检查语法错误

-v: 在执行脚本时,先将脚本的内容输出到屏幕上

-x: 将使用的脚本内容显示到屏幕上