linux shell编程总结

linux shell编程总结

本周学习了unix/linux
shell编程,参考的是《LINUX与UNIX
Shell 编程指南》,David
Tansley著;徐焱,张春萌等译,由机械工业出版社出版的了,往内页那么一翻,都是2000年3月译的了,原书估计会更老,不过图书馆能找到合适于我这种初学者的也许就这么本了,将就着的吧。

这本书是以Bourne
shell这个UNIX系统都支持的标准shell。Bourne
Again shell(BASH)、TCSH
shell和Z
shell它们都是相应的UNIX命令解释程序的增强型版本。BASH
shell是Bourne
shell的高级版本。TCSH
原来是为UNIX的BSD版本开发的C
shell的增强型版本。

1.基本unix/linux命令

(1)
setuid,guid

作用:
suid意味着如果某个用户对属于自己的shell脚本设置了这种权限,

那么其他用户在执行这一脚本时也会具有其属主的相应权限。

guid执行相应脚本的用户将具有该文件所属用户组中用户的权限

例:chmod
4755

(2)
chmod,chown,chgrp

作用:修改权限

格式:chmod
[who] operator [permission] filename

who:u(文件属主)
g(同组用户)
o(其他用户)
a(所有用户)

operator:
+(增加权限)
-(取消权限)
=(设定权限)

permission:r(读)
w(写)
x(执行)
s(文件属主和组set-ID)
t(粘性位*)
l(给文件加锁,使其他用户无法访问)

例:chmod
ugo+rwx myfile 将myfile文件给u,g,o用户r,w,x的权限

(3)
umask

作用:设置所创建文件/目录的缺省权限

格式:umask
[value]

例:umask
022

touch
file1

则file1的权限部分变为:-rw-r--r--

(4)
ln

格式:ln
[-s] source_path target_path

(5)
touch

作用:创建一个空文档

格式:tough
myfile

注解:tough
myfile将创建一个文件myfile

(6)
find

作用:搜索文件

格式:find
pathname -options [-print -exec -ok]

-print:find命令将匹配的文件输出到标准输出

-exec:find命令对匹配的文件执行该参数所给出的shell命令,相应命令的格式为'command'{}
\;

-ok:作用和-exec作用相同。只不过每一步执行都需要用户的确认

-options:(主要的)

-name:按文件名查找

-perm:按文件权限查找

-prune:使find命令不在当前指定的目录中查找

-user:按照文件属主查找

-group:按照文件所属组来查找

-mtime
-n
+n,按照文件的更改时间来查找,-n表示文件更改时间距现在n天以内,+n表示文件更改时间距现在n天以前;此外,还有-atime,-ctime选项,和-mtime选项类似

-type:查找某一类型的文件,诸如:b(块设备文件),d(目录),c(字符设备文件),p(管道文件),l(符号链接文件),f(普通文件)

-size
n[c]:查找文件长度为n块的文件

例:

在当前目录及其子目录中查找所有的"*.txt"文件

find
. -name "*.txt" -print

在当前目录下查找文件权限位为755的文件,即文件属主可以读、写、执行,其他用户可以读、执行的文件

find
. -perm 755 -print

在当前目录下查找除目录以外的所有类型的文件

find
. ! -type d -print

用ls
-l 命令列出所匹配的文件

find
. -type f -exec ls -l {} \;

在/logs目录中查找更改时间在5日以前的文件并删除它们

find
logs -type f -mtime +5 -exec rm {} \;

(7)echo

作用:显示文本行或变量,或者把字符串输入到文件

格式:echo
string

例:

给出提示符,并输入值给变量name

echo
"What's your name:\c"

read
name

(8)pg

作用:显示文件

格式:pg
filename

(9)read

作用:读入值给变量

格式:read
var

例:read
name 从键盘读入字符到name变量

(10)cat

作用:显示文件

格式:cat
filename

(11)tee

作用:把输出的一个副本输送到标准输出,另一个副本拷贝到相应的文件中

格式:tee
filename

例:who
| tee who.out 使用who命令,结果输出到屏幕上,同时保存在who.out文件中

(12)grep(全局正则表达式)

作用:允许对文本文件进行模式查找,如果找到匹配模式,grep打印包含模式的所有行

格式:grep
[options] 基本正则表达式[文件]

常用options值:

-c
只输出匹配行的计数

-i
不区分大小写(只适用于单字符)

-h
查询多文件时不显示文件名

-l
查询多文件时只输出包含匹配字符的文件名

-n
显示匹配行及行号

-s
不显示不存在或无匹配文本的错误信息

-v
显示不包含匹配文本的所有行

例:grep
"sort" *.doc 在当前目录下所有的.doc文件中查找字符串"sort"

grep
"48<tab>" data.f 抽取字符串后有一个<Tab>键

grep
'[0-9]\{3\}\.[0-0\[3\}\.' ipfile 要抽取其中所有nnn.nnn的IP地址(原文印刷错误?)

(13)awk

格式:awk
[-f field-separator] 'command' input-file(s)

===============================================================================

awk条件操作符

===============================================================================

操作符描述操作符描述

<
小于>=
大于等于

<=
小于等于~
匹配正则表达式

==
等于!
不匹配正则表达式

!=
不等于

===============================================================================

awk内置变量

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

ARGC
命令行参数个数

ARGV
命令行参数排列

ENVIRON
支持队列中系统环境变量的使用

FILENAME
awk浏览的文件名

FNR
浏览文件的记录数

FS
设置输入域分隔符,等价于命令行-F选项

NF
浏览记录的域个数

NR
已读的记录数

OFS
输出域分隔符

ORS
输出记录分隔符

RS
控制记录分隔符

注:awk中所采用的正则表达式的符号要比grep和sed多两个:+(匹配一个或多个字符),?(匹配模式出现率)

例:

awk
'{if($4~/Brown/) print $0}' grade.txt 如果field-4包含了Brwon,打印该行

awk
'$3 == "48" {print $0}' grade.txt 精确匹配,如果field-3等于了"48",则打印该行

awk
'{if( $1=="p1" && $4=="p2" ) print $0}'
grade.txt 同时满足两个条件,则打印该行

awk
'{if( $1=="p1" || $4=="p2" ) print $0}' grade.txt
只要满足其中一个条件,则打印该行

(14)expr
用于计算或数值测试

格式:expr
argument operator argument

例:expr
10 + 10 其结果为20

expr
30 / 3 其结果为10

expr
30 \* 3 其结果为90,使用乘号时,必须用反斜线屏蔽其特定含义。

expr
rr + 1 当rr非整数时,将返回错误,此处为"expr:non-numeric
argument"

2.文件名的匹配

特殊的匹配符号:

*
匹配文件名中的任何字符串,包括空字符串

?
匹配文件名中的任何单个字符串

[...]
匹配[]中包含的任何字符

[!...]
匹配[]中非感吧号!之后的字符

例:

显示所有以.doc结尾的文件名

ls
*.doc

显示以cl开头,后面跟任何字符串,最后以.sed结尾的文件名

ls
cl*.sed

显示任意两个字符开头,接着是r,后面跟任何字符的文件

ls
??r*

显示以i或o开头的文件名

ls
[io]*

匹配所有以log.开头,后面跟随一个数字,然后可以是任意字符串的文件名

ls
log.[0-9]*

匹配所有以log.开头,使用[!0-9]来表示非数字开头的字符串

ls
log.[0-9]*

3.文本过滤

===============================================================================

基本元字符集及其含义

===============================================================================

^
只匹配行首

$
只匹配行尾

*
一个单字符后紧跟*,匹配0个或多个此单字符

[]
匹配[]内字符。可以是一个单字符,也可以是字符序列,用-表示范围

如用[1-5]代替[12345]

\
用来屏蔽一个元字符的特殊含义。如$
. ' " * ^ | ( ) \ + ?

.
匹配任意单字符

pattern\{n\}
用来匹配前面pattern出现次数。n为次数

pattern\{n,\}m
含义同上,但次数最少为n

pattern\{n,m\}
含义同上,但pattern出现次数在n与m之间

===============================================================================

例:

^$
匹配一个空行

^.$
匹配只包含一个字符的行

compu*t
匹配字符u
0次或多次,这个可匹配computer,

A\{2\}B
匹配字母A出现两次,并以B结尾

A\{2,4\}B
匹配字母A出现2到4次之间

4.特定shell变量

===============================================================================

$#
传递到脚本的参数个数

$*
以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过9个

$$
脚本运行的当前进程ID号

$!
后台运行的最后一个进程的进程ID号

$@
与$#相同,但是使用时加引号,并在引号中返回每个参数

$-
显示shell使用的当前选项,与set命令功能相同

$?
显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误

===============================================================================

其他:$0(脚本名字)
$1 $2 $3 ...$9

5.shell输入与输出

5.1文件描述符

===============================================================================

文件描述符文件

0
输入文件——标准输入

1
输出文件——标准输出

2
错误输出文件——标准错误

===============================================================================

注:标准输入是文件描述符0,它是命令的输入,缺省是键盘,也可以是文件或其他命令的输出

标准输出是文件描述符1,它是命令的输出,缺省是屏幕,也可以是文件

标准错误是文件描述符2,它是命令错误的输出,缺省是屏幕,也可以是文件

5.2
重定向:<,<<,>,>>

===============================================================================

command>filename
把标准输出重定向到一个新文件中

command>>filename
把标准输出重定向到一个文件中(追加)

command
1>filename 把标准输出重定向到一个新文件中

command>filename
2>&1 把标准输出和标准错误一起重定向到一个文件中

command
2>filename 把标准错误重定向到一个新文件中

command
2>>filename 把标准错误重定向到一个文件中(追加)

command
>>filename 2>&1 把标准输出和标准错误一起重定向到一个文件中(追加)

command
<filename >filename 2
command命令以filename文件作为标准输入,以filename2文件作为标准输出

command
<&m 把文件描述符m作为标准输入

command
>&m 把标准输出重定向到文件描述符m中

command
<&- 关闭标准输入

===============================================================================

例:

#############################################################################

#!
/bin/sh

#
f_desc

#把文件描述符4指定为标准输入,然后打开stock.txt文件

exec
4<&0 0<stock.txt

#读入2行文本

read
line1

read
line2

#作为标准输入的文件描述符4被关闭

exec
0<&4

#显示两个变量的内容

echo
&line1

echo
&line2

#############################################################################

5.3管道:
命令1|命令2

who
| awk '{print $1"\t"$2}'

6.条件测试

格式1:test
condition

格式2:[condition]

===============================================================================

文件测试状态

===============================================================================

-d
目录-s
文件长度大于0,非空

-f
正规文件-w
可写

-l
符号链接-u
文件有suid位设置

-r
可读-x
可执行

===============================================================================

组合测试:-a
逻辑与-o逻辑或!逻辑否

例:[-w
results.txt -a -w scores.txt

echo
$?

检查上面两个文件是不是都是可写的

字符串测试string_operator
可为=(相等)
!=(不相等)
-z(空串)
-n(非空串)

格式1:test
"string"

格式2:test
string_operator "string"

格式3:test
"string" string_operator "string"

格式4:[string_operator
string]

格式5:[string
string_operator string]

数值测试numeric_operator可为-eq(相等),-ne(不相等),-gt(大于),-lt(小于),-le(小于等于),-ge(大于等于)

格式1:"number"
numeric_operator "number"

格式2:["number"
numeric_operator "number"]

7.命令执行顺序&&
,||, (), {}

&&

格式:命令1
&& 命令2

说明:命令1返回真(即返回0,成功被执行)后,命令2才能够被执行

例:/apps/bin目录将会被移到/apps/dev/bin目录下,如果它没有被成功的执行,就不会删除/apps/bin目录

mv
/apps/bin /apps/dev/bin && rm -r /apps/bin

||

格式:命令1
|| 命令2

说明:命令1未执行成功,那么就执行命令2

例:拷贝文件没成功的话,就显示错误.

cp
word.txt word.bak || echo "cp file failed!"

()
{}

格式:(命令1;命令2;...)
{命令1;命令2;...}

8.控制流结构if...then...else...fi,case,for,until,while,break,continue

1)返回码

观察:echo
$?

退出:exit
n (n为一数字)

break
n ==>跳出指定的循环个数。如break
2则跳出2个循环

continue
==>跳出循环当前步

2)流控制if...then...else...fi

if
condition1

then

command1

elif
condition2

then

command2

else

command3

fi

例1:

##############################################

#!
/bin/sh

#
ifwr

LOGFILE=test.txt

echo
$LOGFILE

if
[ ! -w "$LOGFILE" ]; then

echo
"You cannot write to $LOGFILE " >&2

fi

##############################################

例2:

##############################################

#!
/bin/sh

#
ifcp

#下面用2>&1重定向标准错误,去除了系统产生的错误和系统输出

if
cp myfile myfile.bak >/dev/null 2>&1 ; then

echo
"good copy"

else

echo
"`basename $0`:error could not copy the files " >&2

fi

##############################################

例3:

##############################################

#!
/bin/sh

#
ifcp

#将脚本参数传入系统命令

#此处检测目录是否为空

DIRECTORY=$1

if
[ "`ls -A $DIRECTORY`" = ""] ; then #也可用if
[$# -lt 1] 来代替判断语句

echo
"$DIRECTORY is indeed empty"

else

echo
"$DIRECTORY is not empty " >&2

fi

##############################################

例4:

##############################################

#!
/bin/sh

#
ifmkdir

#将脚本参数传入系统命令

#此处检测目录是否为空

DIRECTORY=$1

if
[ "$DIRECTORY" = ""] ; then

echo
"Usage: `basename $0` directory to create"

exit
1

fi

if
[ -d $DIRECTORY ]

then
: # do nothing

else

echo
"The directory does exist"

echo
-n "Create it now? [y..n] :"

read
ANS

if
[ "$ANS" = "y" ] || [ "$ANS" = "Y"
]

then

echo
"creating now"

mkdir
$DIRECTORY >/dev/null 2>&1

if
[ $? != 0 ]; then

echo
"Errors createing the directory $DIRECTORY" >&2

exit
1

fi

else
: # do nothing

fi

fi

##############################################

3)case控制流

case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

格式:

==========================================================================

case
值in

模式1)

命令1

....

;;

模式2)

命令2

....

;;

esac

==========================================================================

注:每一模式必须以右括号结束,取值可以为变量或常数。

匹配发现取值符合某一模式后,其间所有命令开始执行直至“;;”

取值将检测匹配每一个模式,一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。

如果无一匹配模式,使用星号*捕获该值,再接受其他输入

模式部分可能包括元字符,与在命令行文件扩展名例子中使用过的匹配模式类型相同,即

*(任意字符),?(任意单字符),[..](类或范围中任意字符)

例1:

##############################################

#!
/bin/sh

#
caseterm

echo
"choices are..vt100,vt102,vt220"

echo
-n "enter your terminal type :"

read
TERMINAL

case
$TERMINAL in

vt100|vt102)
TERM=vt100

;;

vt220)
TERM=vt220

;;

*)
echo "`basename $0`:Unknow response" >&2

echo
"setting it to vt100 anyway,so there"

TERM=vt100

;;

esac

export
TERM

echo
"Your terminal is set to $TERM"

##############################################

例2:

##############################################

#!
/bin/sh

#
caseparam

if
[ $# !=1 ] ; then

echo
"Usage:`basename $0` [start|stop|help]" >&2

exit
1

fi

#assign
the parameter to the variable OPT

OPT=$1

case
$OPT in

start)
echo "starting..`basename $0`"

;;

stop)
echo "stopping..`basename $0`"

;;

help)

;;

*)
echo "Usage:`basename $0` [start|stop|help]"

;;

esac

##############################################

4)循环

for格式

==========================================================================

for
变量名in 列表

do

命令1

命令2

.....

命令n

done

==========================================================================

注:列表可以包含替换,字符串和文件名

例1:

##############################################

#!
/bin/sh

#
for_i

for
loop in 1 2 3 4 5 #for loop in "orange red blue grey"

do

echo
$loop

done

##############################################

例2:

##############################################

#!
/bin/sh

#
for_ls

for
loop in `ls `

do

echo
$loop

done

##############################################

例3:

#for
params,不使用in列表选项时,实际上等价于

#for
params in "$@" 或

#for
params in "$*"

##############################################

#!
/bin/sh

#
for_param

for
loop in "$@" # 也可以是"$*,"
这可以从命令行中取得参数

do

echo
$loop

done

##############################################

until(不常用)格式

==========================================================================

until
条件

do

命令1

命令2

.....

命令n

done

==========================================================================

例1:监视文件系统容量,当它达到一定水平时通知超级用户

##############################################

#!
/bin/sh

#
until_mon

LOOK_OUT=`df
| grep /logs | awk '{print $5}' | sed 's/%//g'`

echo
$LOOK_OUT

until
["$LOOK_OUT" -gt "90" ]

do

echo
"Filesystem..logs is nearly full" | mail root

exit
0

done

##############################################

while格式

==========================================================================

while
命令

do

命令1

命令2

.....

命令n

done

==========================================================================

例1:从文件中读取数据,使用重定向以保证从文件中读取数据

#########################################################################

#!
/bin/sh | SAVEDIFS=$IFS

#
whileread | IFS=:

while
read LINE | while read NAME DEPT ID

do
| do

echo
$LINE | echo -e "$NAME\t $DEPT\t $ID"

done
<names.txt | done <names.txt

|
IFS=$SAVEDIFS

#########################################################################

上面右边使用IFS将域分隔符改为;号而不是空格或tab键

测试数据names.txt:

Louise
Conrad:Accounts:Acc889

Peter
James:Payroll:PR483

#########################################################################

死循环格式

while
:

do

命令

done

例2:

#########################################################################

#!
/bin/sh

#
menu

#set
the date,user and hostname up

MYDATE=`date
+%d/%m/%Y`

THIS_HOST=`hostname
-s`

USER=`whoami`

#loop
forever !

while
:

do

#
clear the screen

tput
clear

#
here documents starts here

cat
<<MAYDAY

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

User:$USER
Host:$THIS_HOST Date:$MYDATE

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

1
: List files in current directory

2
: Use the vi editor

3
: See who is on the system

H
: Help screen

Q
: Exit Menu

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

MADAY

#
here document finished

echo
-e "\tYour Choice [1,2,3,H,Q] >"

read
CHOICE

case
$CHOICE in

1)
ls

;;

2)
vi

;;

3)
who

;;

H|h)

cat
<<MAYDAY

this
is the help screen,nothing here yet to help you !

MAYDAY

;;

Q|q)
exit 0

;;

*)
echo -e "\t\007Unknown user response"

;;

esac

echo
-e -n "\tHit the return key to continue"

read
DUMMY

done

#########################################################################

等我总结完了,后面又翻了一本书《Linux
编程命令详解》第二版,Richard
Petersen著,梁普选,刘玉芬等译,2001年由电子工业出版社出版的,这本书总结得更好了。呵呵,看来,凡事都是有个过程的。

===================================================================

特殊符号的总结

1、{}
大括号:

用法一:通配符扩展

eg:
ls my_{finger,toe}s

这条命令相当于如下命令的组合:

ls
my_fingers my_toes

eg:
mkdir {userA,userB,userC}-{home,bin,data}

我们将得到userA-home,
userA-bin, userA-data, userB-home, userB-bin,userB-data,userC-home,
userC-bin, userC-data,这几个目录

用法二:可用于语句块的构造,语句之间用回车隔开。如果你想在某些使用单个语句的地方(比如在AND或OR列表中)使用多条语句,你可以把它们括在花括号{}中来构造一个语句块。

eg:

{

grep
-v "$cdcatnum" $strack_file > $temp_file

cat
$temp_file > $strack_file

echo

cat
-n file1

}
(注:以上大括号中的四句命令够成了一个语句块)

用法三:参数扩展

${name:-default}
使用一个默认值(一般是空值)来代替那些空的或者没有赋值的变量name;

${name:=default}使用指定值来代替空的或者没有赋值的变量name;

${name:?message}如果变量为空或者未赋值,那么就会显示出错误信息并中止脚本的执行同时返回退出码1。

${#name}
给出name的长度

${name%word}
从name的尾部开始删除与word匹配的最小部分,然后返回剩余部分

${name%%word}
从name的尾部开始删除与word匹配的最长部分,然后返回剩余部分

${name#word}
从name的头部开始删除与word匹配的最小部分,然后返回剩余部分

${name##word}
从name的头部开始删除与word匹配的最长部分,然后返回剩余部分

(注,name为变量名,word为要匹配的字符串)

用法三在处理字符串和未知变量时,是很有用的。

2、[]
中括号:

用法一:通配符扩展:

允许匹配方括号中任何一个单个字符

eg:
ls /[eh][to][cm]*

相当于执行ls
/etc /home(若有/eom目录,就相当于会执行ls
/etc /home /eom)

注:在mkdir命令下不能扩展

用法二:用于条件判断符号:

[]符号可理解为指向test命令的一个软链接,所以其用法可完全参照test,将test位置替换为[便可。

eg:
if [ "$?" != 0 ] 等价于if
test "$?" != 0

then
echo "Executes error"

3、`command`
反引号:`command`与$(command)的含义相同,都是返回当前执行命令的结果

eg:
#!/bin/sh

for
file in $(ls f*.sh);do

lpr
$file

done

exit
0

该例实现了扩展f*.sh给出所有匹配模式的文件的名字。

4、'string'
单引号和"string"
双引号

双引号:如果想在定义的变量中加入空格,就必须使用单引号或双引号,

单、双引号的区别在于双引号转义特殊字符而单引号不转义特殊字符

eg:
$ heyyou=home

$
echo '$heyyou'

$
$heyyou ($没有转义)

eg:
$ heyyou=home

$
echo "$heyyou"

$
home (很明显,$转义了输出了heyyou变量的值)

5、$#
它的作用是告诉你引用变量的总数量是多少;

$$
它的作用是告诉你shell脚本的进程号;

$*
以一个单字符串显示所有的脚本传递的参数。等价于$1
$2 $3.......;

$@
与$*基本类似(参见序号7),但在数组赋值时有些不同;

$?
前一个命令的退出码;

$-
显示shell使用的当前选项;

$!
最后一个后台运行的进程ID号。

6、$((...))
语法:对括号内的表达式求值(fantaxy注:千万别乱加入空格)

eg:

#!/bin/sh

x=0

hile
[ "$x" -ne 10 ];do

echo
$x

x=$(($x+1))

done

exit
0

7、shell中几种特殊的参数变量的引用

$1、$2、$3……${10}、${11}、${12}……
:表示脚本传入的的各个参数,注意当需表示两位数以后的参数时数字要用花括号括起。

$@
列出所有的参数,各参数用空格隔开

$*:
列出所有的参数,各参数用环境变量IFS的第一个字符隔开

8、命令列表:

AND列表statement1
&& statement2 && statement3 &&
…:只有在前面所有的命令都执行成功的情况下才执行后一条命令

OR列表statement1
|| statement2 || statement3 ||
…:允许执行一系列命令直到有一条命令成功为止,其后所有命令将不再被执行

eg:#!/bin/sh

touch
file_one

rm
-f file_two

if
[ -f file_one ] && echo "hello" && [ -f
file_two ] && echo " there"

then

echo "in if"

else

echo "in else"

fi

exit
0

上例的输出为:

hello

in
else

关于AND列表与OR列表,在逻辑判断中很使用,下面就举一个其最常用的例子:

[
condition ] && command for true || command for false:

当条件为真时,执行commandfor
true ,当条件为假时,执行command
for false

9、:
冒号:内建空指令,返回值为0

eg:
$ :

$
echo $?

$
0

while:
(该语句结构可实现一个无限循环)

10、;
分号:
在shell
中,担任"连续指令"功能的符号就是"分号"

eg:cd
~/backup ; mkdir startup ; cp ~/.* startup/.

11、#
井号:表示符号后面的是注解文字,不会被执行;

*
匹配文件名中的任何字符,包括字符串;

?匹配文件名中的任何单个字符。

~
代表使用者的home
目录

12、\
倒斜线:放在指令前,有取消aliases(别名)的作用;放在特殊符号前,则该特殊符号的作用消失;放在指令

的最末端,表示指令连接下一行(使得回车符无效,只起换行作用)

14、!
感叹号:通常它代表反逻辑的作用,譬如条件侦测中,用!=
来代表"不等于"

15、**
次方运算:两个星号在运算时代表"次方"
的意思

eg:let
"sus=2**3"

echo
"sus = $sus"

$
sus = 8

上一篇:java中instanceof和getClass()的作用


下一篇:第五节:详细讲解Java中的接口与继承