1. 控制结构

1.1 if...then

if...then控制结构的语法如下:

if test-command
thencommands
fi

if 语句测试test-command返回的状态,并基于这个状态转移控制。if结构的结束由fi语句标记,例如:

echo -n "Word 1: "
read word1
echo -n "Word 2: "
read word2
if test "$word1" = "$word2"
thenecho  "Match"
fi

在BASH中,test是一个内置命令,也就是说它是shell的一部分,同时还有一个单独的工具test。对于数值比较测试有以下几种测试选项:-ne(不等)、-eq(等于)、-gt(大于)、-ge(大于等于)、-lt(小于)以及-le(小于等于)。对于字符串比较可以用=(等于)、!=(不等于)来进行测试比较。特殊变量"$#"表示命令行参数的个数,例如:

if test $# -eq 0
thenecho "Error"exit 1
fi

可以使用test来判断文件参数状态或两个文件参数的关系,如果test内置命令带有"-f"选项和一个参数(第1个参数$1),那么它就可用来检查参数所指定的文件,例如:

if test -f "$1"
thenecho "$1 is  a regular file"
elseecho "$1 is not a regular file"
fi
test内置命令的选项
选项 功能
-d 检查文件是否存在以及该文件是否是文件目录。
-e 检查文件是否存在。
-f 检查文件是否存在以及该文件是否是一个普通文件。
-r 检查文件是否存在以及该文件是否可读。
-s 检查文件是否存在以及该文件是否大于0字节。
-w 检查文件是否存在以及该文件是否可写。
-x 检查文件是否存在以及该文件是否可执行。

"[]"为test的同义词,可以把test的参数用方括号括起来,例如:

if [$# -eq 0]
thenecho "..."exit 1
fi

1.2 if...then...else

在if结构中引入else语句使其为分支结构,语法如下:

if test-command
thencommands
elsecommands
fi

如同换行符一样,分号可以结束一条命令,因此,可以把then与if放在同一行,并在then的前面加一个分号,例如:

if test-command; thencommands
elsecommands
fi

如果test-command返回true状态,if结构执行then和else语句之间的命令,然后把控制转向fi后面的语句。如果test-command返回false状态,if结构执行else语句后面的命令。

1.3 if ...then...elif

if...then...elif控制结构的语法如下:

if test-commands
thencommands
elif test-command
thencommands
elsecommands
fi

elif语句组合了if语句与else语句,使得可以嵌套多个if...then...else结构。else语句和elif语句之间的差别在于每个else语句必须与一个fi语句配对,而多个嵌套的elif语句只需要一个fi语句。

1.4 for...in

控制结构for...in的语法如下所示:

for loop-indexin argument-list
docommands
done

for...in结构把argument-list中的第1个参数赋给loop-index变量,并执行do和done语句之间的命令。 在脚本把控制传给done语句之后,结构把arguments-list的第2个参数赋给loop-index变量并再一次执行do和done之间的命令。

1.5 for

for控制结构语法如下:

for loop-index
docommands
done

在for结构中,loop-index用命令行参数中的每个参数值取代,一次执行一个。除了loop-index变量的取值来源,for结构与for...in结构是相同的。for结构通常依次根据每个参数执行一个命令序列。

1.6 while

while控制结构的语法形式如下:

while test-command
docommands
done

只要测试条件的返回值为真,while结构语句就要执行do与done语句之间的命令。在每次循环之前,while结构都要检查测试条件。一旦测试语句的返回值为假,while结构语句就把控制传递到done语句之后的程序段。

1.7 until

until语句与while语句的语法结构相似,区别只在于until在语句的结束测试。until的语法结构如下:

dountil test-commands
done

1.8 break与continue

利用break和continue语句可以在for、while或until语句中产生中断。break语句可以跳出循环,把控制直接转移到done语句之后的内容。continue语句把控制传到done语句, 并继续执行循环。

1.9 case

case控制结构是一种多分支选择机制,具体选择哪个分支依赖于测试串和某个分支类型之间的匹配情况,case控制结构的语法如下:

case test-string inpattern-1)
commands-1
;;pattern-2)
commands-2
;;pattern-3
commands-3
;;
esac

case结构中的匹配类型类似于一个模糊文件引用,实际上匹配类型可以包括表中的任何字符或字符串:

匹配类型
类型 功能
* 匹配任意字符串,用作默认的case匹配。
? 只匹配单个字符。
[...] 定义一个字符类,对处在方括号的每个字符依次进行单字符匹配。
| 分离带有选择的选项,这些选项满足case结构的一个特别的分支。

1.10 select

select控制语句首先显示一个菜单,然后根据用户选择给变量赋予相应的值,最后执行一系列命令。select控制结构的语法形式如下:

select varname [in arg...]
docommands
done

select结构显示的内容为arg条目的菜单。假如忽略键盘输入和参数列表,select控制语句会用位置参数来取代arg条目。

2. 参数和变量

2.1 文件描述符

一个进程无论从文件中读内容还是向文件中写内容之前必须先打开这个文件。当一个进程打开文件时,Linux中常给这个文件分配一个数字,即文件描述符。一旦打开某个文件,进程无论是读或者是写该文件都要靠文件描述符来进行操作。当进程不再需要该文件时,它必须关闭该文件同时也要释放文件描述符。

一个典型的Linux进程在启动时包括3个已打开的文件:标准输入、标准输出和标准错误输出。在bash中使用exec内置命令打开文件,例如:

exec n> outfile
exec m< infile

第一行是打开一个输出文件outfile,并给它赋予文件描述符n,第二行是打开一个输入文件infile,并给它分配文件描述符m。符号"<&"的作用是复制一个输入文件描述符,符号">&"的作用是复制一个输出文件描述符。可以通过把两个文件描述符指向同一个文件的方法来复制文件描述符,例如:

exec n<&m

2.2 数组变量

bash支持一维数组作为变量。数组的下标是整数并以数字0作为起始,格式如下:

name=(element1 element2...)

可以按照如下方式引用数组中的某个元素:

echo ${NAMES[1]}

下标"[*]"和"[@]"的作用都是提取出整个数组元素,但是当它们加上双引号使用时工作机制却不同。"@"符号的含义是把原数组的内容复制到一个新数组中,生成的新数组和原来是一样的。但是"*"符号是把原数组中的所有元素当成一个元素复制到新数组中,生成的新数组只有一个元素,例如:

A=("${NAME[*]}")
B=("${NAME[@]}")

把操作符"${#NAME[*]}"放在一个数组变量的前面可以返回数组中元素的个数,例如:

echo ${#NAME[*]}

把上面操作符中的"*"符号替换为数组的下标就能返回数组中对应元素内容的长度,例如:

echo ${#NAME[1]}

也可以将数组下标放在赋值语句的左边以便对相应的数组元素进行赋值,例如:

NAME[1]=John

2.3 变量局部性

进程在遇到默认变量时,一般看成是声明位置处的局部变量。除非将变量声明为可访问的全局变量,否则shell脚本不能访问用户在登录shell中声明的变量。在bash下,export命令可以使父进程的变量对子进程来说是可使用的,例如:

export name=John
echo "$name"
#subscript
echo "$name"

由于函数运行的环境通常与其被调用的环境相同,所以其中变量是显示的被shell和调用它的函数一起共享的,例如:

function name() {echo $mynamemyname=John
}
myname=Marry
name #Marry
echo $myname #John

在函数中使用局部变量,可以使用typeset内置命令,例如:

function name() {typeset mynamemyname=Johnecho $myname
}
myname=Marry
name #John
echo $myname #Marry

2.4 特殊参数

shell把执行shell的进程的PID号存储在特殊参数"$$"中,例如:

echo $$

把PID号包含在一个文件名中对于创建一个唯一的文件名是非常有益的,这种方法常常用在shell脚本中用来创建临时文件的名称。

后台运行的进程的PID号存储在符号"$!"中,例如:

sleep 60 &
echo $!

一个进程无论由于何种原因停止运行,它都要向父进程返回一个exit状态,返回的状态可以被认作是条件码或者返回码,"$?"中存储着上一个命令的返回状态码,例如:

ls
echo $?

2.5 位置参数

参数"$#"保存了命令行上除命令自身之外的参数的个数,例如:

echo "This script was called with $# arguments."

参数"$0"中保存了用来执行程序命令的名称,该参数被设置为0是因为它出现在命令行上第1个参数的前面,例如:

echo "The command used to run this script is $0"

命令行上的第1个参数由"$1"替换,第2个由参数"$2"替换,一直到"$n",一旦n的值超过9,数字两边就要加上大括号,例如:

echo "First 5 arguments are $1 $2 $3 $4 $5"

变量"$*"包含了所有的命令行参数,例如:

echo "All arguments are $*"

参数"$*"和"$@"除了它们在加上双引号用法不同外,其他的用法都相同。使用参数"$*"只能产生一个参数,而参数"$@"则生成一串参数,其中每个位置参数仍然是一个单独的参数。

2.6 左移命令行参数

利用shift内置命令可以移动每个命令行参数,向左移动时,第1个参数被丢弃,第2个参数变成第1个参数,依次类推。已经丢弃的命令无法找回,例如:

echo "arg1=$1 arg2=$2 arg3=$3"
shift
echo "arg1=$1 arg2=$2 arg3=$3"

2.7 初始化命令行参数

set命令是用来初始化命令行参数变量的。set命令把set后跟的一个或几个参数赋值给位置参数,这些位置参数以$1打头,例如:

set this is it
echo $1 $2 $3

2.8 扩展空变量和未设置变量

表达式${name}扩大为变量name的值。如果name变量为空或还没有设置,bash就将${name}扩展成一个空串。可以通过给变量加上一个修饰符来选择几个选项:变量使用默认值、使用默认值并将其赋给变量、显示错误。

修饰符":-"使用一个默认值来替代那些空的或者没有赋值的变量,格式如下:

${name:-default}

例如:

${APP_PATH:-/home/test}

修饰符":-"不能改变理的值,但如果希望修改脚本中空变量或未赋值变量的默认值,修饰符":="可以实现这个功能,格式如下:

${name:=default}

shell按照扩展表达式${name:-default}的方式来扩展表达式${name:=default},同时把变量name的值设置为default的值。

shell脚本中常用冒号":"后跟扩展表示符":="来给任意一个空变量或者未赋值的变量赋值。冒号通常给命令行上其后的符号赋值而不会去执行后面的命令,格式如下:

: ${name:=default}

有时,通过设置默认的变量值不能给脚本中某些变量提供一个合理的值,这时":?"修饰符就会显示出错误信息并中止脚本的执行同时返回退出码1,格式如下:

${name:?message}

3. 内置命令

3.1 type

使用type命令可以显示出系统命令的相关信息,例如:

type cat echo

3.2 read

通过使用read命令,脚本可以接受用户的输入并将输入信息存入到用户创建变量中。通过使用read命令,脚本可以接受用户的输入信息储存到变量中,例如:

read myvar
echo "Entered: $myvar"

read命令有一些特性可以使使用read变得更加方便。如果不想指定一个变量来保存read的输入内容,bash会把用户的输入放在一个名为REPLY的变量中。通过用选项-p来显示用户提示,例如:

read -p "Go ahead:"
echo "Entered: $REPLY"

如果用户输入大于read拥有的变量数,read将按照变量的顺序先给每个变量分配一个非空内容,到最后一个变量时,把剩下的内容全部分配到这个变量中。

3.3 exec

使用exec内置命令有两个主要的目的:第1个是使用它可以不用创建新进程来执行一个命令,第2个是使用它可以重定向来自shell脚本内部的文件描述符。一般假如shell执行的命令不是来自shell内部,那么执行这个命令就会创建一个新的进程,这个新进程继承来自父进程的环境变量而不会继承父进程中没有使用export导出的变量。相反exec执行命令时常覆盖当前的进程。

可以使用如下语法来使exec运行一个命令:

exec command arguments

由于exec并不创建新进程,所以执行速度非常快,并且由于exec不能把控制返回到原程序中,所以通常把它作为最后一个命令。

使用exec也可以把来自shell脚本内部的文件描述符的信息重定向到其他文件中,例如:

exec > outfile 2> errfile

当以这种方式使用exec命令时,当前的进程不会被新的进程取代。

3.4 trap

在Linux中,信号可以用来报告用户产生的中断,还可以用来报告诸如错误的系统调用、管道中断、非法指令和其他状况等。使用trap内置命令来捕获一个或多个信号,以便于用户在收到一个特殊的信号时采取相应的动作。

可以按如下语法使用trap命令:

trap ['commands'] [signal]

可选项command指出了当脚本在捕获到由signal指定的信号后应采取的指令。signal可以是信号的名字或者信号的编号,如INT或2。如果没有command命令,那么trap命令就会把trap重置到初始化状态。

当执行过commands的内容后,shell会恢复执行commands命令离开处的脚本。在收到一个信号后,如果用户想使用trap阻止脚本退出但又不想运行任何一个显式命令,可以给commands指定一个空串,例如:

trap '' 15

3.5 kill

kill内置命令用来给一个进程或者作业发送信号,kill命令的语法格式如下:

kill [-signal] PID

signal是信号的名字或者信号的编号,PID是要接收信号的进程号,可以使用%n的形式指定一个作业编号来替代PID,如果省略了signal,kill命令就发出一个TERM信号,例如:

kill -TERM %1

3.6 getopts

getopts内置命令用来解析命令行参数,语法结构如下:

getopts optstring varname [arg...]

其中,optstring是合法的字母选项列表,varname变量保存了每次接收的选项的值,arg是即将被处理的可选参数。若存在arg参数,getopts就去处理命令行参数,若optstring以冒号":"作为开始,则由脚本负责产生错误信息,否则就由getopts产生错误信息。

getopts命令使用变量OPTIND(选项索引)和OPTARG(选项参数)来保存和选项相关的值。当shell脚本启动时,OPTIND的值被设置为1,以后每次当getopts命令发现一个参数,它就增加OPTIND的值,该值与下一个将要被处理的选项的索引相等。如果选项中含有参数,bash就把参数的值赋给变量OPTARG。

为了指定某个选项含有参数,在optstring中相应的字母后面加上一个冒号,例如:

while getopts do:t:r arg
docase $arg ind) echo "-d";;o) echo "-o : $OPTARG";;t) echo "-t : $OPTARG";;r) echo "-r";;esac
done

4. 表达式

4.1 算术表达式

bash能够处理算术赋值,并能够对各种算术表达式求值,shell中有很多方法可以用来进行算术赋值,其中一种是使用let,例如:

let "VALUE = VALUE * 10 + NEW"

let语句中不需要在变量前面加美元符号,但必须将单个的变量或者带有空格的表达式用双引号引起来。由于let的每个参数被解释为一个独立的表达式,所以可以在一行上给多个变量进行赋值,例如:

let "COUNT = COUNT + 1" VALUE=VALUE*10+NEW

可以利用((expression))的语法结构来同时表示算术表达式和逻辑表达式,例如:

if ((30 < age && age < 60)); thenecho "$age"
fi

4.2 逻辑表达式

条件表达式的语法形式如下:

` expression `

在expression中必须在变量的名字前面加上美元符,执行该表达式的结果与命令test一样,返回的是一个状态,例如:

if [[ 30 < $age && $age < 60 ]]; thenecho "$age"
fi

也可以使用test命令的关系比较符:"-gt"、"-ge"、"-lt"、"-le"、"-eq"和"-ne"。操作符">"和"<"按字母顺序比较字符串,操作符"="进行类型匹配比较,比如"[[ artist = a* ]]"返回为真。

4.3 字符串模式匹配

bash提供了可操作路径名字符串以及其他字符串类型匹配操作符,这些操作符可以从字符串的前缀或后缀中删去字符串。

字符串操作符
操作符 功能
# 去除最小匹配前缀。
## 去除最大匹配前缀。
% 去除最小匹配后缀。
%% 去除最大匹配后缀。

这些操作符的语法形式如下:

${varname op pattern}

op是上表中的操作符,pattern是一个匹配类型,例如:

MYFILE=/usr/local/src/test.c
echo ${MYFILE%.c}

4.4 操作符

算术扩展和算术赋值使用了和C语言相同的语法、操作符的运算优先级以及表达式的关联关系。下表按照优先等级递减的顺序列出了这些操作符:

操作符
操作符类型 功能
后置 var++ 后置加
后置 var-- 后置减
前置 ++var 前置加
前置 --var 前置减
一元 - 一元减
一元 + 一元加
取反 ! 布尔取反
取反 ~ 二进制取反
取幂 ** 幂指数
乘法 * 乘法运算
除法 / 除法运算
取模 % 取模运算
加法 + 加法
减法 - 减法
二进制移位 << 左移
二进制移位 >> 右移
比较运算符 <= 小等于
比较运算符 >= 大等于
比较运算符 < 小于
比较运算符 > 大于
相等 = 相等
不等 != 不相等
二进制位运算符 & 二进制AND运算
二进制位运算符 ^ 二进制XOR运算
二进制位运算符 | 二进制OR运算
布尔 && 布尔AND运算
布尔 || 布尔OR运算
条件赋值 ? : 三元操作符
赋值 =、*=、/=、%=、+=、-=、<<=、>>=、&=、^=、|=赋值操作
逗号 , 逗号操作符

管道操作符的优先级比所有操作符都高,例如:

cmd1 | cmd2 || cmd3 | cmd4 && cmd5 | cmd6

前置和后置操作符要与变量结合在一起使用,例如:

echo $((--N+3))

取模操作符取出第1个操作数被第2个除之后的余数,例如:

echo $((15%7))

使用布尔操作符所得的结果要么是0,要么是1,布尔操作符被称为短路操作符,如果仅仅通过左边的操作数就可以得出最终的结果,那么右边的操作数就可以不用赋值。

变量"$?"中保存了前面命令执行后的退出状态,例如:

true || false && false
echo $?

转载于:https://blog.51cto.com/hanviseas/1127378

[Linux] BASH程序设计相关推荐

  1. 《Linux 高级程序设计(第三版)》——导读

    ** 前言 ** Linux应用开发是目前最为广泛的软件开发内容之一,同时也是从事Linux内核及驱动开发的基础.<Linux高级程序设计>一书经过两次出版,收到了大量的读者来信,对本书提 ...

  2. Linux Bash小结1

    1.Linux Bash变量类型 A 本地变量 B 环境变量 C 位置变量 D 特殊变量 需要注意的是: 父SHELL和子SHELL是两个不同的进程,他们不会共享本地变量. 环境变量对当前SHELL及 ...

  3. linux文件删除指定内容,Linux bash删除文件中含“指定内容”的行功能示例

    本文实例讲述了Linux bash删除文件中含"指定内容"的行功能.分享给大家供大家参考,具体如下: #!/bin/sh # 功能: 删除文件中含"指定内容"的 ...

  4. linux -bash: ipconfig: command not found 解决方法

    linux -bash: ipconfig: command not found 解决方法 参考文章: (1)linux -bash: ipconfig: command not found 解决方法 ...

  5. linux bash中too many arguments问题的解决方法

    linux bash中too many arguments问题的解决方法 参考文章: (1)linux bash中too many arguments问题的解决方法 (2)https://www.cn ...

  6. linux bash shell之declare

    linux bash shell之declare declare或typeset内建命令(它们是完全相同的)可以用来限定变量的属性.这是在某些编程语言中使用的定义类型不严格的方式.命令declare是 ...

  7. 手把手教你:如何让Windows恋上Linux bash

    4月7日,微软开始向用户推送Windows 10 biuld 14316预览版,该版本不仅在Cortana跨平台支持.Edge浏览器支持和虚拟桌面方面得到了优化,还能够原生支持Linux bash. ...

  8. linux bash shell之变量替换::=句法、=句法、:-句法、-句法、=?句法、?句法、:+句法、+句法

    linux bash shell之变量替换::=句法.=句法.:-句法.-句法.=?句法.?句法.:+句法.+句法 变量替换和变量默认值设置是紧密相关的,至少从概念出发是如此. 参数扩张是将类似于变量 ...

  9. Linux:-bash: ***: command not found

    Linux:-bash: ***: command not found,系统很多命令都用不了,均提示没有此命令. 突然之间linux很多命令都用不了,均提示没有此命令. 这应该是系统环境变量出现了问题 ...

最新文章

  1. [深度学习]Object detection物体检测之概述
  2. 闲谈IPv6-典型特征的一些技术细节
  3. [翻译] MotionBlur
  4. codeforce 570 problem E 51Nod-1503-猪和回文
  5. 随机文件名生成可用于文件上传(图片)
  6. C#.NET禁止一个程序启动多个实例
  7. java怎么来用urlrewrite伪静态化和urlrewrite的配置
  8. anjuta 连接mysql_ubuntu系统下如何实现C/C++开发环境搭建(IDE)
  9. opengl动画_物理动画流体实现流程(Physically Based Fluid Animation)
  10. linux exfat分区格式化,技术|如何在 Linux 上将 USB 盘格式化为 exFAT
  11. springboot 2.0 Redis command timed out的解决
  12. 多项logistic回归系数解释_Logistic回归结果的回归系数和OR值解读
  13. 阿里云ECS建网站(建站)超详细全套完整图文教程!菜鸟必看!
  14. 面试过程中应注意的问题与禁忌
  15. 熔断机制什么意思_熔断机制是什么意思?
  16. 大脑分区与功能简介汇总
  17. delta对冲策略_期权的Delta对冲策略对比分析
  18. 苹果手机如何一键备份手机里的照片和视频?
  19. 面试后说hold什么意思_面试快结束时,如果面试官对你说这几句话,说明你被淘汰了!...
  20. R语言与生物统计分析试题

热门文章

  1. 数百万人都在使用的9款无线路由器易受226个缺陷影响
  2. 苹果 “Find My” 功能中的漏洞可暴露用户的位置信息
  3. Bouncy Castle 加密库修复高危的认证绕过漏洞
  4. 能让程序员瞬间崩溃的五个瞬间,共鸣的同学请举手!
  5. lenovo Win10 安装 Androd Studio 新版本编程开发的软件
  6. Tip:在使用AjaxControlTookit的控件时响应事件
  7. Redis 未授权访问漏洞利用
  8. 5 个给 Linux 新手的最佳包管理器
  9. 一个广为人知但鲜有人用的技巧:对象池
  10. 1.MAC中MySql的环境配置