> 文档中心 > Linux-Shell学习笔记教程,快速学习

Linux-Shell学习笔记教程,快速学习


Linux-Shell

思维导图结构:
在这里插入图片描述

介绍

shell是什么呢?其实是我们一直在用的,所有的命令都是通过shell去实现的,看来自菜鸟教程的介绍:

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

它所说的界面,可能就是我们一直用的黑框框吧,是不是一说界面会想到图形化界面,还在纳闷呢!哈哈

大家已经写过一个脚本了hello world,在之前的章节中,我们已经写过一个小小的脚本,万能的hello world;

快速上手

菜鸟教程对这里部分基础写的非常好,这里大量参考菜鸟教程Linux-shell部分加上自己的理解,帮大家进行一遍梳理;

这里我们再重新认识下,新建一个文件为hello.sh,使用vim在里面编辑:

#!/bin/bash   #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行echo "Hello World !"     #命令用于向窗口输出文本。

当然了,这个时候还不能运行./hello.sh试一下,提示权限不够,是因为文件并没有执行权限,我们需要给文件添加执行权限,chmod +x hello.sh,再次执行,成功!

[root@localhost test]# vim hello.sh[root@localhost test]# ./hello.sh-bash: ./hello.sh: 权限不够[root@localhost test]# chmod +x hello.sh[root@localhost test]# lshelloNos.txt  hello.sh  helloS.txt  hello.txt[root@localhost test]# ./hello.shhello,world[root@localhost test]# 

注意,一定要写成 ./hello.sh,而不是 hello.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 hello.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./hello.sh 告诉系统说,就在当前目录找。

所以知道为什么执行命令需要加./了吧

可能还有疑惑,后缀名就一定.sh是这样吗?不是的,我们来试一下,我修改了文件的名字,为hello.t再次执行还是没有问题,因为这里不像C、java、python需要固定的后缀名.c .java .py 文件名是什么都没有任何问题,.sh后缀是一种很好的规范,到时候你和别人都可以知道这是一个shell脚本文件:

[root@localhost test]# mv hello.sh hello.t[root@localhost test]# lshelloNos.txt  helloS.txt  hello.t  hello.txt[root@localhost test]# ./hello.thello,world[root@localhost test]# 

Shell语法

变量

变量定义:

定义变量时,变量名不加美元符号($,我们使用变量时需要),如:

your_name=“runoob.com”

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

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线 _
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

有效的 Shell 变量名示例如下:

RUNOOBLD_LIBRARY_PATH_varvar2

无效的变量命名:

?var=123user*name=runoob

使用变量

使用一个定义过的变量,只要在变量名前面加美元符号即可,如:

实例
your_name="qinjx"echo $your_nameecho ${your_name}

只读变量

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

下面的例子尝试更改只读变量,结果报错:

实例
#!/bin/bashmyUrl="https://www.google.com"readonly myUrlmyUrl="https://www.runoob.com"

运行脚本,结果如下:

/bin/sh: NAME: This variable is read only.

删除变量

使用 unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用。unset 命令不能删除只读变量。

实例
#!/bin/shmyUrl="https://www.runoob.com"unset myUrlecho $myUrl

变量类型

运行shell时,会同时存在三种变量:

  • 1) 局部变量 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 2) 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • 3) shell变量 shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

Shell 字符串

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。

单引号

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

双引号

双引号的优点:

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

拼接字符串

实例

your_name="runoob"# 使用双引号拼接greeting="hello, "$your_name" !"greeting_1="hello, ${your_name} !"echo $greeting  $greeting_1# 使用单引号拼接greeting_2='hello, '$your_name' !'greeting_3='hello, ${your_name} !'echo $greeting_2  $greeting_3

输出结果为:

hello, runoob ! hello, runoob !hello, runoob ! hello, ${your_name} !

获取字符串长度

实例
string="abcd"echo ${#string}   # 输出 4echo ${#string[0]}   # 输出 4

变量为数组时,KaTeX parse error: Expected '}', got '#' at position 2: {#̲string}** 等价于 *…{#string[0]}:

提取子字符串

实例

以下实例从字符串第 2 个字符开始截取 4 个字符:

string="runoob is a great site"echo ${string:1:4} # 输出 unoo

查找子字符串

查找字符 io 的位置(哪个字母先出现就计算哪个):

实例
string="runoob is a great site"echo `expr index "$string" io`  # 输出 4注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

Shell 数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。

类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

定义数组

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

数组名=(值1 值2 ... 值n)例如:array_name=(value0 value1 value2 value3)或者array_name=(value0value1value2value3)还可以单独定义数组的各个分量:array_name[0]=value0array_name[1]=value1array_name[n]=valuen

注意:可以不使用连续的下标,而且下标的范围没有限制。

读取数组

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

${数组名[下标]}

例如:

valuen=${array_name[n]}

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

echo ${array_name[@]}

获取数组的长度

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

实例
# 取得数组元素的个数length=${#array_name[@]}# 或者length=${#array_name[*]}# 取得数组单个元素的长度lengthn=${#array_name[n]}

shell注释

单行注释

# 开头的行就是注释,会被解释器忽略。

通过每一行加一个 # 号设置多行注释,像这样:

#--------------------------------------------# 这是一个注释

多行注释

多行注释还可以使用以下格式:

:<<EOF注释内容...注释内容...注释内容...EOF

实例

EOF 也可以使用其他符号:

:<<'注释内容...注释内容...注释内容...':<<!注释内容...注释内容...注释内容...!

Shell运算

Shell 传递参数

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$nn 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

实例

以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名(包含文件路径):

实例

#!/bin/bash# author:菜鸟教程# url:www.runoob.comecho "Shell 传递参数实例!";echo "执行的文件名:$0";echo "第一个参数为:$1";echo "第二个参数为:$2";echo "第三个参数为:$3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh $ ./test.sh 1 2 3Shell 传递参数实例!执行的文件名:./test.sh第一个参数为:1第二个参数为:2第三个参数为:3

另外,还有几个特殊字符用来处理参数:

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。 如"$*“用「”」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ ∗ 相 同 , 但 是 使 用 时 加 引 号 , 并 在 引 号 中 返 回 每 个 参 数 。 如 " *相同,但是使用时加引号,并在引号中返回每个参数。 如" 使"@“用「”」括起来的情况、以"$1" “ 2 " … " 2" … " 2""n” 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

逻辑运算

不做过多赘述了,这里大家直接去参考菜鸟教程吧!

看我列出的知识点:

  1. bool
  2. test
  3. if···then
  4. while
  5. for
  6. until
  7. case … esac
  8. break
  9. continue
  • 算数运算符
  • 关系运算符
  • 布尔运算符
  • 字符串运算符
  • 文件测试运算符

echo我们已经使用了很多了,printf也差不多,大家看一眼即可;

来吧给大家打开一个,传送门

Shell函数

linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。

shell中函数的定义格式如下:

定义格式:

[ function ] funname [()]{    action;#代码体    [return int;]  #返回值}

说明

  • 1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
  • 2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)

例子

#!/bin/bashdemoFun(){    echo "这是我的第一个 shell 函数!"}echo "-----函数开始执行-----"demoFunecho "-----函数执行完毕-----"

输出结果:

-----函数开始执行-----这是我的第一个 shell 函数!-----函数执行完毕-----

下面定义一个带有return语句的函数:

#!/bin/bashfunWithReturn(){    echo "这个函数会对输入的两个数字进行相加运算..."    echo "输入第一个数字: "    read aNum#read读取输入的数值    echo "输入第二个数字: "    read anotherNum    echo "两个数字分别为 $aNum$anotherNum !"    return $(($aNum+$anotherNum))}funWithReturnecho "输入的两个数字之和为 $?"

输出类似下面:

这个函数会对输入的两个数字进行相加运算...输入第一个数字: 1输入第二个数字: 2两个数字分别为 1 和 2 !输入的两个数字之和为 3

函数返回值在调用该函数后通过 $? 来获得。

函数参数

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…

带参数的函数示例:

#!/bin/bashfunWithParam(){    echo "第一个参数为 $1 !"    echo "第二个参数为 $2 !"    echo "第十个参数为 $10 !"    echo "第十个参数为 ${10} !"    echo "第十一个参数为 ${11} !"    echo "参数总数有 $# 个!"    echo "作为一个字符串输出所有参数 $* !"}funWithParam 1 2 3 4 5 6 7 8 9 34 73

输出结果:

第一个参数为 1 !第二个参数为 2 !第十个参数为 10 !第十个参数为 34 !第十一个参数为 73 !参数总数有 11 个!作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

注意 10 不 能 获 取 第 十 个 参 数 , 获 取 第 十 个 参 数 需 要 10 不能获取第十个参数,获取第十个参数需要 10{10}。当n>=10时,需要使用${n}来获取参数。

另外,还有几个特殊字符用来处理参数:

参数处理 说明
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

函数与命令的执行结果可以作为条件语句使用。

要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false。

实践小程序

作业

  1. 完成一个二人猜年龄游戏,程序需要询问第一个人的年龄(x)是多少,然后再询问第二个人猜测第一个人的年龄(y)是多少,

y猜的比x大,反馈猜大了,相反,反馈猜小了,x=y时,游戏结束,恭喜答对;

  1. 大家还可以写下算法小程序,归并排序、快速排序、冒泡排序······

IO重定向

什么是IO重定向呢?

我们拆开理解,IO就是输入和输出,我们知道我们的程序都是在对数据的输入输出(传递),那什么是重定向呢,就是改变输入输出的方向,我们知道默认模式下,输入输出都是在终端,你对终端输入,程序对终端输出,但有时候我们又不想输入输出重定向,比如:日志和错误,都是应该保存文件中,供我们找出问题,查找问题,这时候就需要输入输出重定向了;

很简单:只需要知道、 >&、>、<<

命令 说明
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 之间的内容作为输入。

需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。

这里做一个小案例即可:

我里有个程序,需要输入日志到执行位置,以便后期维护和查看:

程序代码:

#!/bin/bashecho '程序执行成功,没有bug'

需要输入到相同目录下的log文件中:

#新建文件和程序[root@localhost ~]# cd /home/test[root@localhost test]# lshelloNos.txt  helloS.txt  hello.t  hello.txt[root@localhost test]# vim logTest.sh[root@localhost test]# lshelloNos.txt  helloS.txt  hello.t  hello.txt  logTest.sh[root@localhost test]# cat logTest.sh #!/bin/bashecho '程序执行成功,没有bug'[root@localhost test]# chmod +x logTest.sh #执行程序没有问题[root@localhost test]# ./logTest.sh 程序执行成功,没有bug

查看结果

#将程序执行日志放入log中,我们可以看到,我们程序执行产生的日志都会在log中,供我们维护和查看[root@localhost test]# ./logTest.sh > log[root@localhost test]# lshelloNos.txt  helloS.txt  hello.t  hello.txt  log  logTest.sh[root@localhost test]# cat log程序执行成功,没有bug[root@localhost test]# 

那么>>就是想文件末尾追加,以及>&<<不难理解了哈!

小结

希望篇文章对大家有帮助,可以用来参考!