shell基础语法

shell基础语法

指定脚本要使用的 Shell

#!/bin/bash

上面这句代码中, /bin/bash 是 Bash 程序在大多数 Linux 系统中的存放路径,而最前面的 #! 被称作 Sha-bang,或者 Shebang。

在计算机科学中,Shebang(也称为 Hashbang )是一个由井号和叹号构成的字符串 #! ,其出现在文本文档的第一行的前两个字符。
在文档中存在 Shebang 的情况下,类 Unix 操作系统的进程载入器会分析 Shebang 后的内容,将这些内容作为解释器指令,并调用该指令,并将载有 Shebang 的文档路径作为该解释器的参数。

给脚本文件添加可执行的权限

chmod +x test.sh

以调试模式运行

随着我们渐渐深入 Shell 编程,你也许会写出很长的 Shell 脚本,代码一多很可能就会有 Bug。

因此,我们需要学习如何调试一个脚本程序。用法如下:

bash -x test.sh

我们直接调用 Bash 这个 Shell 程序,并且给它一个参数 -x (表示以调试模式运行),后面再跟上要调试运行的脚本文件。

shell变量

定义变量的时候=左右不要加空格!

引号

我们可以用引号来界定包含空格的字符串。

引号一共有三种:

类型表示
单引号
双引号"
反引号`

根据引号类型不同,Bash 的处理方式也会不同。

单引号

我们从单引号开始学习吧。美式键盘中,单引号( ’ ) 位于 Enter 键(回车键)的左方。

之前的例子里,我们也已经使用过单引号了。

#!/bin/bash

message='Hello World'
echo 'The message is $message'

正如之前我们测试的一样,如果变量被包含在单引号里面,那么变量不会被解析,美元符号( $ )保持原样输出。

显示:

The message is $message

因为:单引号忽略被它括起来的所有特殊字符。

双引号

一般来说,要输入双引号,需要用 “Shift键 + 单引号的按键”。

不同于单引号忽略所有特殊字符,双引号忽略大多数特殊字符,但不包括:美元符号( $ )、反引号( ` )、反斜杠( \ ),这 3 种特殊字符将不被忽略。 不忽略美元符号意味着 Shell 在双引号内部可进行变量名替换。

例如:

#!/bin/bash

message='Hello World'
echo "The message is $message"

执行以上脚本,显示:

The message is Hello World

反引号

反引号 ( ` ) 不太常用,位于键盘的 Tab 键的上方、数字键 1 的左方。

反引号要求 Shell 执行被它括起来的内容。 什么意思呢?我们来看一个例子你就懂了:

#!/bin/bash

message=`pwd`
echo "You are in the directory $message"

运行这个脚本,显示:

You are in the directory /home/pearfl

read : 请求输入

-p :显示提示信息

目前来说,read 命令提供了 -p 参数,p 是 prompt 的首字母,表示“提示”。

-n :限制字符数目

用 -n 参数,我们可以限制用户输入的字符串的最大长度(字符数)。n 是 number 的首字母,是英语“数目”的意思。

-t :限制输入时间

用 -t 参数,我们可以限定用户的输入时间(以秒为单位),也就是说超过这个时间,就不读取输入了。t 是 time 的首字母,是英语“时间”的意思。

-s :隐藏输入内容

用 -s 参数,我们可以隐藏输入内容。一般用不到,但是如果你想要用户输入的是一个密码,那 -s 参数还是有用的。

数学运算

在 Bash 中,所有的变量都是字符串

let 命令可以用于赋值

可用的运算符是以下几种:

运算符号
加法+
减法-
乘法*
除法/
幂(乘方)**
余(整数除法的余数)%

如果你要做带小数的运算,那么需要用到 bc 命令

参数变量

假设,我们可以这样调用我们的脚本文件:

./variable.sh 参数1 参数2 参数3 ...

这些个 参数1,参数2,参数3 … 被称为“参数变量”。

但问题是我们还不知道如何接收这些参数到我们的脚本中。

其实不难,因为这些变量是被自动创建的。

  • $# :包含参数的数目。
  • $0 :包含被运行的脚本的名称 (我们的示例中就是 variable.sh )。
  • $1:包含第一个参数。
  • $2:包含第二个参数。
  • $8 :包含第八个参数。

    以此类推。

数组

例子:

array=('value0' 'value1' 'value2')

上面的语句定义了一个数组变量,名叫 array(array 是英语“数组”的意思),其中包含三个值:value0,value1,value2。

如果要访问其中一个格子的内容,要用到这样的语法:

${array[2]}

以上语句表示数组中编号为 2 的元素(在我们的情况就是 value2 )。

注意:和大多数编程语言一样,Shell 中的数组的下标(index)也基本是从 0 开始的,而不是从 1 开始。因此,第一个元素的编号(下标)就是 0,第二个元素的下标就是 1,以此类推。
不过,也不是所有 Shell 语言的数组下标都是从 0 开始,不少 Shell 语言(例如 Csh,Tcsh,Zsh,等等)的数组下标是从 1 开始的。

判断条件

if : 最简单的条件

if 条件语句的基本格式是这样的:

if [ 条件测试 ]
then 
    做这个
fi

fi 是 if 的反转写法,表示“if 语句结束”。then 是英语“那么”的意思。

“做这个”只有在“条件测试”为真时,才会被执行。

注意:方括号 [] 中的 条件测试 两边必须要空一格。不能写成 [test],而要写成 [ test ]

当然了,if 语句的基本写法还有一种,那就是把 then 写在 if [ 条件测试 ] 后面,如下:

if [ 条件测试 ]; then
    做这个
fi

用这种写法时,在 if 条件判断和 then 之间要加一个分号。

需要注意在 Shell 语言中,“等于”是用一个等号( = )来表示的,这和大多数主流编程语言不同。

else : 否则

既然有“如果”的条件判断,那么也会存在条件不成立的时候

if 和 else 两者配合的逻辑是这样的:

if [ 条件测试 ]
then
    做这个
else
    做那个
fi

也就是:如果“条件测试”为真,那么“做这个”被执行;否则,“做那个”被执行。

elif : 否则,如果

一般来说 if 和 else 已经能满足我们的大部分条件判断需要了,但有些时候,存在好几种情况。

光是 if 和 else 表示的两种对立的情况已经不足以满意要求了,因此我们再来一个关键字:elif 。

elif 是 else if 的缩写,表示“否则 - 如果”。

if, elif 和 else 三者配合的逻辑是这样的:

if [ 条件测试 1 ]
then
    做事情 1
elif [ 条件测试 2 ]
then
    做事情 2
elif [ 条件测试 3 ]
then
    做事情 3
else
    做其他事情
fi

不同的测试类型

在 Bash 中我们可以做三种测试:

  • 测试字符串
  • 测试数字
  • 测试文件
测试字符串

我们之前的课程已经说过:在 Shell 中,所有的变量都是字符串。

因此,要做字符串的测试非常简单。记住以下表格:

条件意义
$string1 = $string2两个字符串是否相等。Shell 大小写敏感,因此 A 和 a 是不一样的。
$string1 != $string2两个字符串是否不同。
-z $string字符串 string 是否为空。z 是 zero 的首字母,是英语“零”的意思。
-n $string字符串 string 是否不为空。n 是英语 not 的首字母,是英语“不”的意思。

测试数字

尽管 Shell 把所有变量都看成字符串,但是我们还是可以做数字的条件测试。记住以下表格:

条件意义
$num1 -eq $num2两个数字是否相等。和判断字符串所用的符号( = )不一样。eq 是 equal 的缩写,是英语“等于”的意思。
$num1 -ne $num2两个数字是否不同。ne 是 not equal 的缩写,是英语“不等于”的意思。
$num1 -lt $num2数字 num1 是否小于 num2。lt 是 lower than 的缩写,是英语“小于”的意思。
$num1 -le $num2数字 num1 是否小于或等于 num2。le 是 lower or equal 的缩写,是英语“小于或等于”的意思。
$num1 -gt $num2数字 num1 是否大于 num2。gt 是 greater than 的缩写,是英语“大于”的意思。
$num1 -ge $num2数字 num1 是否大于或等于 num2。ge 是 greater or equal 的缩写,是英语“大于或等于”的意思。

测试文件

相比于主流编程语言,Shell 的一大优势就是可以非常方便地测试文件:文件存在吗?我们可以写入文件吗?这个文件比那个文件修改时间更早还是更晚?等等。

下表非常丰富:

条件意义
-e $file文件是否存在。e 是 exist 的首字母,表示“存在”。
-d $file文件是否是一个目录。因为 Linux 中一切都是文件,目录也是文件的一种。d 是 directory 的首字母,表示“目录”。
-f $file文件是否是一个文件。f 是 file 的首字母,表示“文件”。
-L $file文件是否是一个符号链接文件。L 是 link 的首字母,表示“链接”。
-r $file文件是否可读。r 是 readable 的首字母,表示“可读的”。
-w $file文件是否可写。w 是 writable 的首字母,表示“可写的”。
-x $file文件是否可执行。x 是 executable 的首字母,表示“可执行的”。
$file1 -nt $file2文件 file1 是否比 file2 更新。nt 是 newer than 的缩写,表示“更新的”。
$file1 -ot $file2文件 file1 是否比 file2 更旧。ot 是 older than 的缩写,表示“更旧的”。

一次测试多个条件

在一个条件测试中,我们可以同时测试多个条件。需要用到两种符号:

符号意义
&&两个 &。表示“逻辑与”。此符号两端的条件必须全为真,整个条件测试才为真;只要有一个不为真,整个条件测试为假。
II两个竖线。表示“逻辑或”。此符号两端的条件只要有一个为真,整个条件测试就为真;只有两个都为假,整个条件测试才为假。

反转测试

我们可以用“否定”来反转测试条件,要用到感叹号( ! )。

case : 测试多个条件

#!/bin/bash

case $1 in
    "Matthew")
        echo "Hello Matthew !"
        ;;
    "Mark")
        echo "Hello Mark !"
        ;;
    "Luke")
        echo "Hello Luke !"
        ;;
    "John")
        echo "Hello John !"
        ;;
    *)
        echo "Sorry, I do not know you."
        ;;
esac

来分析一下上面的程序,因为有很多新的内容:

  • case $1 in$1 表示我们要测试的变量是输入的第一个参数。in 是英语“在…之中”的意思。
  • "Matthew") :测试其中一个 case,也就是 $1 是否等于 "Matthew"。当然,我们也可以用星号来做通配符来匹配多个字符,例如 "M*") 可以匹配所有以 M 开头的字符串。
  • ;; :类似于主流编程语言中的 break;,表示结束 case 的读取,程序跳转到 esac 后面执行。
  • *) :相当于 if 条件语句的 else,表示“否则”,就是“假如不等于上面任何一种情况”。
  • esac :是 case 的反写,表示 case 语句的结束。

循环

Shell 中,主要的循环语句有三种:

  • while 循环
  • until 循环
  • for 循环

while 循环

在 Shell 中,我们最常用的循环是 while 循环。

while 循环的逻辑是这样的:

while [ 条件测试 ]
do
    做某些事
done

当然了,我们也可以像在 if 语句中那样,把关键字 do 放到与条件测试同一行上,但是之间要加分号,如下:

while [ 条件测试 ]; do
    做某些事
done

until 循环

与 while 这个关键字相反的有一个 until 关键字,until 在英语中是“到…为止,直到…时”的意思。

把while改成until就一样了

for 循环

遍历列表

for 循环可以遍历一个“取值列表”,基本的逻辑如下:

for 变量 in '值1' '值2' '值3' ... '值n'
do
    做某些事
done

更常规的 for 循环

刚才我们看到的 for 循环,和主流编程语言中的语法略有不同,不过我们可以借助 seq 命令,来实现类似主流编程语言中的 for 循环的语法。

seq 是 sequence 的缩写,是英语“序列”的意思。

来写一个例子:

#!/bin/bash

for i in `seq 1 10`
do
    echo $i
done

函数

函数的定义

定义(或创建) Shell 函数是非常容易的。有两种方式:

函数名 () {
    函数体
}

或:

function 函数名 {
    函数体
}
  • 这两种方式都是可行的。看你个人喜好用哪一种方式。

  • 函数名后面跟着的圆括号里不加任何参数:这一点与主流编程语言很不相同。C 语言,Java,C++ 等语言中,函数的圆括号中是可以放置参数的(也就是函数的一部分输入),但是 Shell 中的函数的圆括号里不能放置参数

  • 函数的完整定义必须置于函数的调用之前。

传递参数

在 Shell 函数中,我们给它传递参数的方式其实很像给 Shell 脚本传递命令行参数。我们把参数直接置于函数名字后面,然后就像我们之前 Shell 脚本的参数那样:$1$2$3等等

我们来看一个例子:

#!/bin/bash

print_something () {
    echo Hello $1
}

print_something Matthew
print_something Mark
print_something Luke
print_something John

返回值

Shell 的函数却没办法做到。但是 Shell 的函数可以返回一个状态,有点类似一个程序或命令退出时会有一个退出状态,表明是否成功。

Shell 函数要返回状态,也用 return 这个关键字( return 是英语“返回”的意思)。

一般来说,返回状态 0 表示一切顺利;一个非零值表示有错误。

值得一提的是exit和return有很多有意思的相同点,但exit是系统级的比return更强大,return仅在函数中使用,exit可以在任何地方使用,有兴趣的可以了解其中的区别

变量作用范围

变量的作用范围意味着一个 Shell 脚本的哪些部分可以访问到这个变量。

默认来说,一个变量是“全局的”(global),意味着在脚本的任何地方都可以访问它。

我们也可以创建局部(local)变量。当我们在函数中创建局部变量时,这个变量就只能在这个函数中被访问。

要定义一个局部变量,我们只要在第一次给这个变量赋值时在变量名前加上关键字 local 即可( local 是英语“本地的”的意思)。

#!/bin/bash

local_global () {
    local var1='local 1'
    echo Inside function: var1 is $var1 : var2 is $var2
    var1='changed again'   # 这里的 var1 是函数中定义的局部变量
    var2='2 changed again' # 这里的 var2 是函数外定义的全局变量
}

定义局部变量有一个好处,就是可以防止被脚本的其它地方的代码意外改变数值。

在函数中,尽量用局部变量。只有实在不行才用全局变量,毕竟全局变量不太安全。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值