这周我学习了linux课本第10章

首先总结一下第十章的主要内容

*一、sh脚本
sj脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句。

1 开头

程序必须以下面的行开始(必须方在文件的第一行):

#! /bin/sh

符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。

当编写脚本完成时,如果要执行该脚本,还必须使其可执行。

要使编写脚本可执行:

编译 chmod +x filename 这样才能用./filename 来运行

这里对chomd命令进行详细解释一下:

Linux/Unix 是多人多工作业系统,所有的档案皆有拥有者。利用 chown 可以将档案的拥有者加以改变。一般来说,这个指令只有是由 系统管理者

(root)所使用,一般使用者没有权限可以改变别人的档案拥有者,也没有权限可以自己的档案拥有者改设为别人。只有系统管理者(root)才 有这样的权

限。

使用方式 : chmod [-cfvR] [–help] [–version] mode file…

说明 : Linux/Unix 的档案调用权限分为三级 : 档案拥有者、群组、其他。利用 chmod 可以藉以控制档案如何被他人所调用。

mode : 权限设定字串,格式如下 : [ugoa...][[+-=][rwxX]...][,...],其中
u 表示该档案的拥有者,g 表示与该档案的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者皆是。

  • 表示增加权限、- 表示取消权限、= 表示唯一设定权限。
    r 表示可读取,w 表示可写入,x 表示可执行,X 表示只有当该档案是个子目录或者该档案已经被设定过为可执行。
    -c : 若该档案权限确实已经更改,才显示其更改动作
    -f : 若该档案权限无法被更改也不要显示错误讯息
    -v : 显示权限变更的详细资料
    -R : 对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更)
    --help : 显示辅助说明
    --version : 显示版本

详情可跳转查看:https://blog.csdn.net/ichen820/article/details/115524278?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166298990316800182732675%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166298990316800182732675&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2

所有sh程序基本都执行相同的任务。

二、sh脚本和C程序

高级语言主要指需要编译的语言。如C/C++,Java,C#。脚本语言主要指解释型语言,编写的代码无需编译器编译,直接使用解释器放入虚拟机执行。

1、shell是个脚本语言,也是应用程序与内核进行交互的桥梁(一个让开发者与内核交互的软件)。

比如我们计算机的运行状态等我们是无法肉眼来查看的,但是通过shell我们就能看到他的数据,其他一些应用程序,比如浏览器、音乐播放器等获得内核所

掌管的音频、显卡等驱动的帮助。

shell也是个脚本语言,我们可以将一系列的操作放入一个文件中,并给予这个文件可执行的权限,我们就可以一下运行文件中的所有的指令,比如我们有一

系列的操作经常使用,但是一个一个的打是在太麻烦了,我们可以将他写到一个脚本中,只需一次运行所有的操作就完成了。

而C语言是另一种高级的计算机语言,他可以开发很多软件,其实shell也是用c写的

2、sh是一个解释程序,逐行读取sh脚本文件会直接执行这些行。而C程序必须先编译链接到一个二进制可执行文件,然后通过主sh的子进程运行二进制可执

行文件。

3、在C程序中,每个变量必须有一个类型,例如char、int、float,但是在sh脚本文件中,每个变量都是字符串(只有一种类型)。

4、每个C程序必须要有一个main函数,每个函数必须定义一个返回值类型和参数,sh脚本不需要main函数,在sh脚本中,第一个可执行语句是程序的入口

点。

5、平均每行脚本语言代码执行成百上千条机器指令,高级语言则大约为五条。其中的原因之一是脚本语言使用了解释器,更大的原因是脚本语言的操作更加

强大。脚本语言的代码量和编程时间都少于高级语言。

三、命令行参数

Shell编程中的命令行参数(位置参数)与C程序中的main函数传参类似。这些位置参数使用$N表

示,N为正整数,表示命令行传入的第N个参数。N从0开始进行标记,与C语言中的数组表示的方

式相同。例如,$1表示传递给脚本程序的第一个参数,并依此类推。$0表示程序本身的名字。

命令行参数使用如例所示。

 1	#! /bin/sh
 2	
 3	VAR=$1               #将变量$1的值赋值给变量VAR
 4	echo "VAR = $VAR"

输出结果如下所示,执行脚本时传入命令行第一个参数haha,则$1被赋值为haha,再赋值给变量

VAR,可见输出VAR的值为haha。

权限不足的问题

我发现我在终端输入

bash a.sh
sh ./a.sh

都是可以正常执行的。

但是当输入./a.sh时,就提示我permission denied,权限不足的问题

我查找了原因,发现是因为我没有添加chomd +x a.sh的缘故

在linux里,source、sh、bash、./都可以执行shell script文件,但是他们有所不同

1、source

source a.sh
在当前shell内去读取、执行a.sh,而a.sh不需要有"执行权限"

source命令可以简写为"."

. a.sh

注意:中间是有空格的。

2、sh/bash

sh a.sh
bash a.sh

都是打开一个subshell去读取、执行a.sh,而a.sh不需要有"执行权限"

通常在subshell里运行的脚本里设置变量,不会影响到父shell的。

3、./

./a.sh
#bash: ./a.sh: 权限不够
chmod +x a.sh
./a.sh

打开一个subshell去读取、执行a.sh,但a.sh需要有"执行权限"

可以用chmod +x添加执行权限

4、fork、source、exec

使用fork方式运行script时, 就是让shell(parent process)产生一个child process去执

行该script,当child process结束后,会返回parent process,但parent process的环境

是不会因child process的改变而改变的。

使用source方式运行script时, 就是让script在当前process内执行, 而不是产生一个child

process来执行。由于所有执行结果均于当前process内完成,若script的环境有所改变, 当然

也会改变当前process环境了。

使用exec方式运行script时, 它和source一样,也是让script在当前process内执行,但是

process内的原代码剩下部分将被终止。同样,process内的环境随script改变而改变。

通常如果我们执行时,都是默认为fork的。

运行结果如下:

我们可以发现,$*和$@都可以输出所有参数,但是他们两个还是有所不同的:

$ 和 $@ 的区别*

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

"$n" 的形式输出所有参数。

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

式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

我们再次修改代码,结果如下图所示:

代码如下:

可见$@加上双引号后,print each param from "$@"和以往不同,此语句后的输出就变成逐字符输出了:

uploading-image-950096.png

运行课本上P237页的的代码:

结果如下:

课本对出现abc0的情况出现做出了以下解释:sh将$10看作是$1与0连接,在回显之前,他会用

abc替换$1,从而将$10打印为abc0。而如果我们加入了{},{$10}就可以被正确打印为L。

shift是位置参数整体向左移动一位,使得$2=$1,$3=$2。

四、sh变量

定义变量时,变量名不加美元符号($,PHP语言中变量需要),如:

your_name="runoob.com"

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

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。

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

  • 不能使用标点符号。

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

除此之外,sh还有很多内置变量,如PATH、HOME、TERM等。所有的sh变量都是字符串,未赋值的sh变量是NULL字符串。

以下节选了一些关于sh变量赋值的知识点,注意:赋值的时候不加美元符号"$",只有输出的时候才: echo $A

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

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

实例


#!/bin/bash

myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.runoob.com"

运行脚本,结果如下:

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

删除变量

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

unset variable_name

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

实例

#!/bin/sh

myUrl="https://www.runoob.com"
unset myUrl
echo $myUrl

以上实例执行将没有任何输出。

五、sh中的引号

bash a.sh后结果如下图所示:

  • 双引号用于保留双引号字符串中的空格,但在双引号内会发生替换

  • 双引号里可以有变量

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

六、sh语句

sh语句包括所有的unix/Linux命令,以及可能的I/O重定向。输入课本示例sh语句后:

七、sh命令

内置命令

linux命令

以下为expr命令的较为详细的使用方法:

https://blog.csdn.net/weixin_33453726/article/details/116885658

我在终端运行时,发现输出的还是字符串,我检查后发现expr 10 + 10,中间的空格是必须加的,否则就会被当成是字符串输出。

管道命令

grep "hello" file.txt | wc -l

上述代码表示为:在file.txt中搜索包含有“hello”的行并计算其行数。在这里grep命令的输出作为wc命令的输入。

重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。

写入文件并覆盖旧文件

追加到文件的尾部,保留旧文件内容。

八、sh比较语句:

while语句:

while condition
do
    command
done

关于我不小心创建了5000个文件夹后来又用while循环把他们删掉的事情。。。

其中 I=$(expr $I + 1)

if else 语句


if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

if else-if else 语法格式:

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

判断两个变量是否相等:

a=10
b=20
if [ $a == $b ]
then
   echo "a 等于 b"
elif [ $a -gt $b ]
then
   echo "a 大于 b"
elif [ $a -lt $b ]
then
   echo "a 小于 b"
else
   echo "没有符合的条件"
fi

for循环:


for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

写成一行:

for var in item1 item2 ... itemN; do command1; command2… done;

case语句:

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

相关链接可见:https://blog.csdn.net/Martin201609/article/details/99577898

九、sh函数

sh函数的定义:


--------方法一--------
function 函数名
{
	命令序列
}

-------方法二-------
函数名()
{
	命令序列
}

调用函数的方法
函数名 [参数1] [参数2]

课本上关于练习判断REG文件的代码

先说明-f的含义:-f filename 如果 filename为常规文件,则为真 。REG文件实际上是一种windows操作系统的注册表脚本文件,

因为用$?判断本身就是逻辑错误的,只要有返回值,就一定退出成功了,这样无论返回值是0还是1,退出成功后$?状态一定为0,所以就如程序运行结果,即使$A是一个目录,得到的结果仍旧是说它是一个REG文件。应该修改成if [ !testfile() ]就是如果返回值不为真,就输出它是一个REG文件。

sh脚本中的相关命令字符:

编写sh代码判断文件是否存在:

​ Shell中的函数可以使用“返回值”的方式来给调用者反馈信息(使用return关键字),获取上一个命令返回值的方式是使用$?–

这是获取函数返回值的主要方式

终端运行结果如下: