这周我学习了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 : 显示版本
所有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关键字),获取上一个命令返回值的方式是使用$?–
这是获取函数返回值的主要方式
终端运行结果如下: