当前位置:首页 > 计算机 > 教程 > 正文内容

Linux Shell 脚本编程知识点总结

康哥工作室4个月前 (02-22)教程1610

Shell 本身是一个用 C 语言编写的程序,它是用户使用 Unix/Linux 的桥梁,用户的大部分工作都是通过 Shell 完成的。Shell 既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。

本文主要是对 LINUX SHELL 脚本编程的知识点总结。

定义变量

语法格式:

variableName="value"

变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 首个字符必须为字母(a-z,A-Z)

  • 中间不能有空格,可以使用下划线(_)

  • 不能使用标点符号

  • 不能使用bash里的关键字(可用help命令查看保留关键字)

使用变量

echo ${your_­name} 变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

for skill in Ada Coffe Action Java
do
echo "I am good at ${skill}Script"
done

如果不给 skill 变量加花括号,写成 echo "I am good at $skillScript",解释器就会把 $skillScript 当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

只读变量

使用 read­only 命令可以将变量定义为只读变量,只读变量的值不能被改变。

#!/bin/bash
myUrl="http://see.xidian.edu.cn/cpp/shell/"
readonly myUrl

删除变量

使用 un­set 命令可以删除变量。语法:

unset variable_name

注意:

  • 变量被删除后不能再次使用

  • unset 命令不能删除只读变量

shell特殊变量

特殊变量列表:

变量含义
$0当前脚本的文件名
$n传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2
$#传递给脚本或函数的参数个数
$*传递给脚本或函数的所有参数
$@传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会讲到
$?上个命令的退出状态,或函数的返回值
$$当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID

$* 和 $@ 的区别:

$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号 ("") 包含时,都以"$1""$2" … "$n" 的形式输出所有参数。

但是当它们被双引号 ("") 包含时,"$*"会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@"会将各个参数分开,以"$1""$2" … "$n" 的形式输出所有参数。

Shell命令替换

echo -e "Value of a is $a \n" #这里 -e 表示对转义字符进行替换。如果不使用 -e 选项,将会原样输出

命令替换的语法:

`command`

注意是反引号,不是单引号,这个键位于 Esc 键下方。

Shell变量替换

变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值

可以使用的变量替换形式:

形式说明
${var}变量本来的值
${var:-word}如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值
${var:=word}如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word
${var:?message}如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值,若此替换出现在Shell脚本中,那么脚本将停止运行
${var:+word}如果变量 var 被定义,那么返回 word,但不改变 var 的值

Shell运算符

expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

例如,两个数相加:

#!/bin/bash
val=`expr 2 + 2`
echo "Total value : $val"

运行脚本输出:
Total value : 4

两点注意:

  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样

  • 完整的表达式要被 包含,注意这个字符不是常用的单引号,在 Esc 键下边

关系运算符列表

a=1

b=2

运算符说明举例
-eq检测两个数是否相等,相等返回 true[ $a -eq $b ] 返回 false
-ne检测两个数是否相等,不相等返回 true[ $a -ne $b ] 返回 true
-gt检测左边的数是否大于右边的,如果是,则返回 true[ $a -gt $b ] 返回 false
-lt检测左边的数是否小于右边的,如果是,则返回 true[ $a -lt $b ] 返回 true
-ge检测左边的数是否大等于右边的,如果是,则返回 true[ $a -ge $b ] 返回 false
-le检测左边的数是否小于等于右边的,如果是,则返回 true[ $a -le $b ] 返回 true

布尔运算符列表

运算符说明举例
! 非运算表达式为 true 则返回 false,否则返回 true[ ! false ] 返回 true
-o 或运算有一个表达式为 true 则返回 true[ $a -lt 20 -o $b -gt 100 ] 返回 true
-a 与运算两个表达式都为 true 才返回 true[ $a -lt 20 -a $b -gt 100 ] 返回 false

字符串运算符列表

运算符说明举例
=检测两个字符串是否相等,相等返回 true[ $a = $b ] 返回 false
!=检测两个字符串是否相等,不相等返回 true[ $a != $b ] 返回 true
-z检测字符串长度是否为0,为0返回 true[ -z $a ] 返回 false
-n检测字符串长度是否为0,不为0返回 true[ -z $a ] 返回 true
str检测字符串是否为空,不为空返回 true[ $a ] 返回 true

文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。

例如,变量 file 表示文件 “/var/www/tu­to­ri­al­s­point/unix/test.sh”,它的大小为 100 字节,具有 rwx 权限。下面的代码,将检测该文件的各种属性:

操作符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true[ -b $file ] 返回 false
-c file检测文件是否是字符设备文件,如果是,则返回 true[ -b $file ] 返回 false
-d file检测文件是否是目录,如果是,则返回 true[ -d $file ] 返回 false
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true[ -f $file ] 返回 true
-g file检测文件是否设置了 SGID 位,如果是,则返回 true[ -g $file ] 返回 false
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true[ -k $file ] 返回 false
-p file检测文件是否是具名管道,如果是,则返回 true[ -p $file ] 返回 false
-u file检测文件是否设置了 SUID 位,如果是,则返回 true[ -u $file ] 返回 false
-r file检测文件是否可读,如果是,则返回 true[ -r $file ] 返回 true
-w file检测文件是否可写,如果是,则返回 true[ -w $file ] 返回 true
-x file检测文件是否可执行,如果是,则返回 true[ -x $file ] 返回 true
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true[ -s $file ] 返回 true
-e file检测文件(包括目录)是否存在,如果是,则返回 true[ -e $file ] 返回 true

Shell字符串

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的

  • 单引号字串中不能出现单引号(对单引号使用转义符后也不行)

双引号的优点:

  • 双引号里可以有变量

  • 双引号里可以出现转义字符

获取字符串长度
string="abcd"
echo ${#string}    #输出 4
提取子字符串:
string="alibaba is a great company"
echo ${string:1:4} #输出liba
查找子字符串:
string="alibaba is a great company"
echo `expr index "$string" is`

Shell数组:shell数组的定义、数组长度

定义数组:

在 Shell 中,用括号来表示数组,数组元素用 “空格” 符号分割开。定义数组的一般形式为:

array_name=(value1 ... valuen)

读取数组:

读取数组元素值的一般格式是:

${array_name[index]}

使用 @ 或 * 可以获取数组中的所有元素,例如:

${array_name[*]}
${array_name[@]}

获取数组的长度:

获取数组长度的方法与获取字符串长度的方法相同,例如:

取得数组元素的个数:

length=${#array_name[@]}

或者

length=${#array_name[*]}

取得数组单个元素的长度:

lengthn=${#array_name[n]}

if else语句

1)、if ... else 语句的语法:

if [ expression ]
then
Statement(s) to be executed if expression is true
fi

说明:如果 ex­pres­sion 返回 true,then 后边的语句将会被执行;如果返回 false,不会执行任何语句。

最后必须以 fi 来结尾闭合 if,fi 就是 if 倒过来拼写,后面也会遇见。

注意:expression 和方括号([ ])之间必须有空格,否则会有语法错误。2)、 if ... else ... fi 语句

if ... else ... fi 语句的语法:

if [ expression ]
then
Statement(s) to be executed if expression is true
else
Statement(s) to be executed if expression is not true
fi

3) 、if ... elif ... fi 语句

if ... elif ... fi 语句可以对多个条件进行判断,语法为:

if [ expression 1 ]
then
Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
Statement(s) to be executed if expression 3 is true
else
Statement(s) to be executed if no expression is true
fi

case esac语句

case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令。case 语句格式如下:

case 值 in
模式1)
command1
command2
command3
;;
模式2)
command1
command2
command3
;;
*)
command1
command2
command3
;;
esac

说明:case 工作方式如上所示。取值后面必须为关键字 in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;。;; 与其他语言中的 break 类似,意思是跳到整个 case 语句的最后。

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

举一个例子:

#!/bin/bash
option="${1}"
case ${option} in
-f) FILE="${2}"
echo "File name is $FILE"
;;
-d) DIR="${2}"
echo "Dir name is $DIR"
;;
*)
echo "`basename ${0}`:usage: [-f file] | [-d directory]"
exit 1 # Command to come out of the program with status 1
;;
esac

运行结果:

$./test.sh
test.sh: usage: [ -f filename ] | [ -d directory ]
$ ./test.sh -f index.htm
$ vi test.sh
$ ./test.sh -f index.htm
File name is index.htm
$ ./test.sh -d unix
Dir name is unix
$

for循环

for 循环一般格式为:

for 变量 in 列表
do
command1
command2
...
commandN
done

说明:列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。

in 列表是可选的,如果不用它,for 循环使用命令行的位置参数。

while循环:

while 循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:

while command
do
Statement(s) to be executed if command is true
done

命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。

until循环

un­til 循环格式为:

until command
do
Statement(s) to be executed until command is true
done

说明:un­til 循环执行一系列命令直至条件为 true 时停止。un­til 循环与 while 循环在处理方式上刚好相反。一般 while 循环优于 un­til 循环,但在某些时候,也只是极少数情况下,un­til 循环更加有用。

com­mand 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。

break和continue命令

break 命令允许跳出所有循环(终止执行后面的所有循环)。

con­tinue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

Shell函数:Shell函数返回值、删除函数、在终端调用函数

注意:Shell 函数必须先定义后使用

Shell 函数的定义格式如下:

function_name () {
list of commands
[ return value ]
}

如果你愿意,也可以在函数名前加上关键字 func­tion:

function function_name () {
list of commands
[ return value ]
}

说明:函数返回值,可以显式增加 re­turn 语句;如果不加,会将最后一条命令运行结果作为返回值。

Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0 表示成功,其他值表示失败。如果 re­turn 其他数据,比如一个字符串,往往会得到错误提示:“nu­meric ar­gu­ment re­quired”。

如果一定要让函数返回字符串,那么可以先定义一个变量,用来接收函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。函数返回值在调用该函数后通过 $? 来获得。

在 Shell 中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1 表示第一个参数,$2 表示第二个参数...,$10 不能获取第十个参数,获取第十个参数需要 ${10}。当 n>=10 时,需要使用 ${n} 来获取参数。

另外,还有几个特殊变量用来处理参数,前面已经提到:

变量含义
$#传递给脚本或函数的参数个数
$*传递给脚本或函数的所有参数
$@传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,请查看Shell特殊变量
$?上个命令的退出状态,或函数的返回值
$$当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID

像删除变量一样,删除函数也可以使用 un­set 命令,不过要加上 .f 选项,如下所示:

$unset .f function_name

如果你希望直接从终端调用函数,可以将函数定义在主目录下的 .pro­file 文件,这样每次登录后,在命令提示符后面输入函数名字就可以立即调用。

重定向深入讲解

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。

  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。

  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,com­mand > file 将 std­out 重定向到 file,com­mand < file 将 stdin 重定向到 file。

1.如果希望 stderr 重定向到 file,可以这样写:
$command 2 > file
2.如果希望 stderr 追加到 file 文件末尾,可以这样写:
$command 2 >> file

说明:上面的数字 2 表示标准错误文件 (stderr)

3.如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:
$command > file 2>&1
或
$command >> file 2>&1
4.如果希望对 stdin 和 stdout 都重定向,可以这样写:
$command < file1 >file2

com­mand 命令将 stdin 重定向到 file1,将 std­out 重定向到 file2。

全部可用的重定向命令列表:

命令说明
command > file将输出重定向到 file
command < file将输入重定向到 file
command >> file将输出以追加的方式重定向到 file
n > file将文件描述符为 n 的文件重定向到 file
n >> file将文件描述符为 n 的文件以追加的方式重定向到 file
n >& m将输出文件 m 和 n 合并
n <& m将输入文件 m 和 n 合并
<< tag将开始标记 tag 和结束标记 tag 之间的内容作为输入

Here Document

Here Doc­u­ment 目前没有统一的翻译,这里暂译为” 嵌入文档 “。Here Doc­u­ment 是 Shell 中的一种特殊的重定向方式,它的基本的形式如下:

command << delimiter
document
delimiter

它的作用是将两个 de­lim­iter 之间的内容 (doc­u­ment) 作为输入传递给 com­mand。

注意:

  • 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进

  • 开始的delimiter前后的空格会被忽略掉

下面的脚本通过 vi 编辑器将 doc­u­ment 保存到 test.txt 文件:

#!/bin/sh
filename=test.txt
vi $filename <<EndOfCommands
i
This file was created automatically from
a shell script
^[
ZZ
EndOfCommands

运行脚本:

$ sh test.sh
Vim: Warning: Input is not from a terminal
$

打开 test.txt,可以看到下面的内容:

$ cat test.txt
This file was created automatically from
a shell script
$

/dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到” 禁止输出 “的效果。

如果希望屏蔽 std­out 和 stderr,可以这样写:

$ command > /dev/null 2>&1

Shell文件包含

Shell 也可以包含外部脚本,将外部脚本的内容合并到当前脚本。

Shell 中包含脚本可以使用:

. filename
或
source filename

两种方式的效果相同,简单起见,一般使用点号 (.),但是注意点号 (.) 和文件名中间有一空格。

例如,创建两个脚本,一个是被调用脚本 sub­script.sh,内容如下:

url="http://see.xidian.edu.cn/cpp/view/2738.html"

一个是主文件 main.sh,内容如下:

#!/bin/bash
. ./subscript.sh
echo $url
执行脚本:
$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$

注意:被包含脚本不需要有执行权限。

source filename 与 sh filename 及./filename执行脚本的区别

1. 当 shell 脚本具有可执行权限时,用 sh file­name 与./file­name 执行脚本是没有区别得。./file­name 是因为当前目录没有在 PATH 中,所有”.” 是用来表示当前目录的。

2.sh file­name 重新建立一个子 shell,在子 shell 中执行脚本里面的语句,该子 shell 继承父 shell 的环境变量,但子 shell 新建的、改变的变量不会被带回父 shell,除非使用 ex­port。

3.source file­name:这个命令其实只是简单地读取脚本里面的语句依次在当前 shell 里面执行,没有建立新的子 shell。那么脚本里面所有新建、改变变量的语句都会保存在当前 shell 里面。

举例说明:

  • 1.新建一个test.sh脚本,内容为:A=1

  • 2.然后使其可执行chmod +x test.sh

  • 3.运行sh test.sh后,echo $A,显示为空,因为A=1并未传回给当前shell

  • 4.运行./test.sh后,也是一样的效果

  • 5.运行source test.sh 或者 . test.sh,然后echo $A,则会显示1,说明A=1的变量在当前shell中


相关文章

网站禁止百度转码取消百度转码

网站禁止百度转码取消百度转码

百度转码—在使用百度搜索时候,经期手转码的内容是随处可见。 百度转码利弊 大多数的移动终端浏览器都不能直接浏览WEB网页,百度就...

PHP Mysql 密码暴力破解脚本

PHP Mysql 密码暴力破解脚本

·································· ·本文非原创  资源来自网络 · ·································· &l...

【iPhone 6 Plus尾巴】如何用神奇的build.prop低调奢华有内涵地装X

【iPhone 6 Plus尾巴】如何用神奇的build.prop低调奢华有内涵地装X

在智能手机市场上苹果的iPhone一直都有着很高的关注度,不过其高昂的价格却让人望而 却步。有些年轻人为了拥有一部iPhone 不惜出租胸部来做广告位,更有甚者还卖身卖肾。其实这又何苦呢。...

判断软件是否捆绑木马

判断软件是否捆绑木马

首先 用多几款查捆绑工具看看有没有捆绑 第二 就算查不到有捆绑也不能掉以轻心,因为工具毕竟是工具,不是万能的误报也是常有的事。用杀软查下,看看报毒的病毒类型,是不是符合工具的类型...

IE浏览器cookie全能管理编辑器

IE浏览器cookie全能管理编辑器

其实关于Cookie这个名词对于我们来讲并不遥远,包括在浏览器中登录QQ帐号验证身份或使用百度搜索网页等等都会在电脑中植入Cookies。但是你 知道如何来查看/管理这些cookies吗?好吧,今天...

你敢说自己真正知道鼠标滚轮怎么用吗?

你敢说自己真正知道鼠标滚轮怎么用吗?

看到这个标题也许大多人会在想:哼,我天天摸鼠标玩电脑,难道我还不会用吗?会不会真正懂得鼠标之“滚轮”的用法只有看完了才知道哦! 1、全自动上下滚屏翻页功能...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。