Linux操作系统笔记——Shell程序设计

简介: Linux操作系统笔记——Shell程序设计

一、Shell脚本的概念


Shell是一种程序设计语言,Shell脚本是一种用Shell编写的脚本程序,其中包含命令。Shell环境有很多种,如C Shell(/usr/bin/csh)、Bourne Again Shell(/bin/bash)、Bourne Shell(/usr/bin/sh或/bin/sh)等等,本教程使用的是Bourne Again,可以通过echo命令输出环境变量$SHELL,该变量保存的是当前用户的初始Shell的路径名称,其路径是用户登录时所启动的Shell,通过echo命令输出该变量,如下:

[yyx@yyx12 ~]$ echo $SHELL


在Linux终端中输入命令:

1667222707518.jpg


二、一个Shell脚本的基本步骤


我们知道可以通过vi/vim命令,用于编辑文件或新建文件,不了解的小伙伴可以看这篇文章(Linux操作系统中的vi/vim 编辑器详解),所以创建Shell脚本的方法与创建文件是一样的,它可以通过编辑器、标准输出重定向等方式来创建,但该文件的扩展名(后缀)应为.sh,一个Shell脚本第一行一般是#!,这是约定好的标记,它用于告诉该Shell脚本需要通过哪种解释器来执行。


例如创建一个Shell脚本,脚本名称为hellolinux.sh,其功能是输出一串英文“Hello Linux!”:

1、通过vi命令创建一个名称为hellolinux.sh的Shell脚本:

[yyx@yyx12 ~]$ su root
...
[root@yyx12 yyx]# vi hellolinux.sh


在Linux终端中输入命令:

1667222814084.jpg

2、切换模式,编辑Shell脚本,第一行为“#!/bin/bash”,通过echo命令输出“Hello Linux!”:

#!bin/bash
echo "Hello Linux!"


在文件中输入:

1667222836866.jpg

编写好脚本后,保存并退出,然后最后一步就是执行该Shell脚本,将会在一会讲到。

我们可以通过cat 命令查看文件内容,输出该文件内容:

[root@yyx12 yyx]# cat hellolinux.sh


在Linux终端中输入命令,如下:

1667222861973.jpg

注:Shell脚本中的注释(说明性语句)是通过“#”开始,被注释的语句不会被Shell解释器执行。


三、赋予Shell脚本执行权限


由于建的仅仅只是一个普通的文本文件,它没有执行权限,不能直接调用该Shell脚本使其执行,此时就要修改Shell脚本的权限,如下通过ls -l命令查看刚刚创建的Shell脚本的权限:

[root@yyx12 yyx]# ls -l hellolinux.sh


在Linux终端中输入命令,可看到该文件的权限是- rw- r- - r- -,即文件拥有者、与拥有者同组的用户和其他用户都没有执行权限:

1667222895244.jpg

要执行该Shell脚本,有两种方法,分别是通过Shell调用脚本和通过chmod命令赋予脚本的可执行权限。


(一)Shell调用脚本


可以直接通过bash命令后跟Shell脚本的名称,即可通过Shell调用脚本(这里的bash是针对于Bourne Again Shell,其他的调用命令不一样),如下调用hellolinux.sh该shell脚本,直接在bash后跟脚本名称:

[root@yyx12 yyx]# bash hellolinux.sh


在Linux终端中输入命令:

1667222920226.jpg

这种方法虽然简单,但它适用于用户跟踪调试大型、复杂的脚本。

例如,写一个Shell脚本,通过环境变量,输出自己的UID和路径。

1、首先创建一个shell脚本,名称为shell1:

1667222933636.jpg

2、编写shell脚本,保存后退出vi编辑器:

#!/bin/bash
echo "You are welcome to use bash."
echo "Cuttent work directory is $PWD."
echo "You are $LOGNAME."


在vi编辑器中输入:

1667222960388.jpg

3、执行该shell脚本:

1667222973561.jpg


(二)chmod命令赋予脚本执行权限


另一种方法是通过chmod命令的字母形式来进行更改,例如这里我们只修改文件拥有者(User)的权限,即通过增加权限(+)符号以及x(可执行)即可完成,另外修改后再通过ls -l命令查看该文件信息:

[root@yyx12 yyx]# chmod u+x hellolinux.sh
[root@yyx12 yyx]# ls -l hellolinux.sh


在Linux终端中输入命令,可见更改权限后的该脚本文件(绿色为可执行文件):

1667223052801.jpg

此时,文件所有者就有了执行该Shell脚本的权限,通过在./后跟调该脚本的名称来执行,这里的./表示的是当前工作目录,这样可以省略路径名称。

[root@yyx12 yyx]# ./hellolinux.sh


四、Shell功能性语句


(一)read命令读入


read命令用于读入一行数据,即从键盘读取输入,在使用重定向时,可以读取文件中的一行数据。

1、例如创建一个Shell脚本,其功能是用户输入用户名后,显示用户名,Shell脚本如下:

#!bin/bash
echo -e "Input your name:\c"
read username
echo "Your name is $username"


echo命令带参数-e,表示开启反斜线的转义功能,使命令行中以反斜线引导的转义符有效,\c表示禁止回车符。

在Linux终端中输入命令,例如我们输入“xiaoming”,此时输入的内容被存放至变量username中,再通过echo命令输出,返回的结果如下:

1667223095477.jpg

2、当然也可以read多个变量,然后输入多个字符串使其传入对应的变量中【这里输入的字符串间隔符由环境变量$IFS确实,通常情况下是空格】,若传入的变量少于变量个数,则剩下的未传入的变量值为空;若传入的变量多于变量个数,首先会依次按照顺序传入对应的变量,而将剩下的未传入的变量全部传至最后一个变量,例如shell脚本:

#!bin/bash
echo -e "please input your name and ID!"
read username ID
echo "Your name is $username,ID is $ID"
#inputing quantity is less than required quantity!
read first second third
echo -e "The first is:$first\nThe second is:$second\nThe third is:$third\n"
#inputing quantity is more than required quantity!
read four five
echo -e "$four\n$five\n"


在Linux终端中输入命令,输入username和ID的值为“xiaoming”、123;first、second、third三个参数只输入前两个参数,然后输出这三个变量;four、five两个参数输入三个参数,然后输出这两个变量:

1667223124514.jpg

例如,编写一个shell脚本,要求用户从屏幕输入数值 X,Y,比较这两个数的大小,如果(x > y ,输出 “x is larger than y”;如果 x = y,则输出"x is equal to y";否则输出 “x is less than y”(这里运用到Shell结构性语句中的if条件语句,后面会有详细讲解),如下创建一个shell脚本,其内容如下:

#!/bin/bash
read X Y
if(($X>$Y))
then
        echo "x is larger than y"
elif(($X==$Y))
then
        echo "x is equal to y"
else
        echo "x is less than y"
fi


在vi编辑器中编辑内容:

1667223149565.jpg

在Linux终端中输入命令,执行该shell脚本:

1667223161778.jpg

3、另外通过在read命令后跟参数-s,可以使输入的数据不显示在终端上,常用于输入密码等,后跟-p参数,可以允许在read命令行中直接指定参数。

例如,创建一个shell脚本,其目的是输入用户的登陆密码:

#!/bin/bash
echo "your username is:yyx"
read -s -p "Please enter your password:" password
echo -e "\nyour password is $password"


在vi编辑器中编辑内容:

1667223183673.jpg

在Linux终端中输入命令,执行该shell脚本,输入密码,可看到在终端上是不显示的:

1667223197657.jpg


(二)tput命令


tput命令可使在对整数进行运算时,使其按照四则运算的规则。

例如,创建一个shell脚本,其目的是计算6-5*2的值:

#!/bin/bash
expr 6 - 5 \* 2


在vi编辑器中编辑内容,由于“*”是具有特殊含义的字符,所以在进行乘法运算时,需在其前加上反斜线来消除其含义进行运算:

1667223226446.jpg

在Linux终端中输入命令,执行该shell脚本:

1667223236024.jpg


(三)expr命令


expr命令用于控制字符页面的显示格式。

其常用的终端显示参数有如下:

参数 功能
bel 终端响铃
bold 字体粗体显示
clear 终端清屏
cup x y 移动光标至x行y列
smso 启动高亮显示模式
rmso 结束高亮显示模式
smul 启动下划线模式
rmul 结束下划线模式
sgr0 关闭所有设置的模式


例如,下列shell脚本,执行后终端字体粗体显示,然后清屏:

#!/bin/bash
tput bold
tput clear
echo "end!"


在Linux终端执行,执行后可见终端字体粗体显示且屏幕上其他内容都被清除:

1667223301198.jpg

通过tput命令后跟sgr0关闭所有模式:

[yyx@yyx12 ~]$ tput sgr0


在linux终端输入命令,可见恢复原样:

1667223324636.jpg


五、Shell结构性语句


(一)if条件语句


1、if……then……fi语句

if……then……fi语句,是if条件语句的单支语句,以if开始,以fi结束(fi只是一个结束标志),其格式如下:

if 条件表达式
then
  命令行
  ……
fi


2、if……then……else……fi语句

if……then……else……fi语句也就是常用的if-else语句,若条件表达式成立,则执行命令行1中的命令;若不成立,则执行命令行2的命令,其格式如下:

if 条件表达式
then
  命令行1
  ……
else
  命令行2
  ……
fi


3、if……then……elif……then……else……fi语句

if……then……elif……then……else……fi语句也就是常用的if-else if-else语句,其中else if语句可以有多个,其格式如下:

if 条件表达式
then
  命令行
  ……
elif 条件表达式
then
  命令行
  ……
…………
else
  命令行2
  ……
fi


例如,创建一个shell脚本,通过用户输入两个数值,然后比较两个数值大小,根据不同结果输出不同的内容,如下:

#!/bin/bash
read X Y
if(($X>$Y))
then
  echo "The first value is greater than the second!"
elif(($X==$Y))
then
  echo "The first value is equal to the second!"
else
  echo "The first value is smaller than the second!"
fi


在vi编辑器中编辑内容:

1667223383510.jpg

在Linux终端输入命令,执行三次,每次输入不同的数值:

1667223395553.jpg


(二)case语句


case语句测试多种取值的变量,通常后跟字符串,然后根据不同的取值进行分支运行,它是以case开始的,以esac结束的,其格式如下:

case 字符串 in
  分支1)
  命令行
  ;;
  分支2)
  命令行
  ;;
  ……
esac


例如,编写一个Shell脚本,名称为shell1.sh,实现输入不同的英文字母,从而输出不同的提示,若没有输入规定的英文字母则输出错误提示,如下表:

输入 输出
m、M、moring、Moring Good morning!
a、A、afternoon、Afternoon Good afternoon!
无以上内容 Your answer is error!


shell脚本如下:

#!/bin/bash
read user_input
case "$user_input" in
  m|M|moring|Moring)
    echo "Good moring!"
    ;;
  a|A|afernoon|Afternoon)
    echo "Good afternoon!"
    ;;
  *)
    echo "Your answer is error!"
    ;;
esac


编写shell脚本,这里注意其他情况直接使用“*)”的形式:

1667223444439.jpg

运行shell脚本,测试结果:

1667223454539.jpg


(三)for循环语句


for循环的格式如下,以done结束语句:

for 变量名称 in 列表
do
  命令行
  ……
done


例如,创建一个shell脚本,其作用是打印1-10数字循环输出:

#!/bin/bash
for i in `seq 10`
do
  echo "The number is $i"
done


在vi编辑器中编辑该脚本:

1667223484806.jpg

运行该shell脚本:

1667223495588.jpg

例如创建一个Shell脚本,其作用是新建一个工作组,名称为class1,并向该工作组添加50个用户,用户名称依次为user1,user2,……,user50,主要就要用到for循环和if语句,for循环内每次新创建一个用户,且名称每次加1,如下:

#!/bin/bash
#by authors yyx
groupadd class1
for((i=1;i<=50;i++))
do
if [$i -lt 10]
then
  username="User0"$i
else
  username="User"$i
fi
useradd -G class1 $username
done


编写Shell脚本:

1667223518983.jpg

运行该shell脚本,并查看/etc/passwd和/etc/group的内容改变:

1667223529402.jpg

1667223541885.jpg


另外若对该题进行改变,创建后再编写一个Shell脚本实现自动删除创建的50个用户的功能,如下代码即可实现:

#!/bin/bash
for((i=1;i<51;i++))
do
  userdel -r user$i
done


(四)while循环语句


while循环的格式如下,while后跟条件表达式,也是以done结束语句:

while 条件表达式
do
  命令行
  ……
done


while循环后跟true,则表示无限循环:

while true
do
  命令行
  ……
done


(五)until循环语句


until循环的格式如下,until语句只有当条件表达式的值为假时,until语句才执行其循环体内的命令,否则退出循环,它也是以done结束语句:

until 条件表达式
do
  命令行
  ……
done


(六)continue和break语句


continue和break语句与其他语言中的一样,它们都用于循环语句内,当遇到continue语句则退出本次循环,而break语句则跳出整个循环。


六、test命令


test命令用于计算条件表达式,其返回值为真或假(条件成立返回退出状态值为0,不成立则为1)。

表达式结果 真或假 代表
条件成立 0
条件不成立 1


【注:这里要注意,与c/c++等编程语言中不一样,刚好相反。】

整数test测试如下表:

参数 作用
-eq =为真
-ne !=为真
-gt >为真
-ge ≥ 为真
-lt <为真
-le ≤为真


文件test测试如下表:

参数 作用
-b 文件存在且为块设备文件
-c 文件存在且为字符设备文件
-d 存在且为目录
-e 文件存在
-f 文件存在且为普通文件
-p 文件存在且为管道文件
-r 文件存在且可读
-w 文件存在且可写
-x 文件存在且可执行
-s 文件存在且大小不为0


例1、例如,创建一个shell脚本,用户输入两个字符串,比较两个字符串,若相同则输出“The two strings are equal!”,不相同则输出“The two strings are different!”,如下:

#!/bin/bash
read str1 str2
if test $str1 = $str2
then
  echo "The two strings are equal!"
else
  echo "The two strings are different!"
fi


在vi编辑器中编辑内容:

1667223663148.jpg

在Linux终端输入命令,执行两次,第一次输入不同的字符串,第二次输入相同的字符串:

1667223677257.jpg


test命令后跟-z参数和字符串,它表示当字符串的内容长度为零时表达式为真,另外还有-n参数和字符串,则表示不为零时表达式为真。

test -z string
test -n string


例2、例如,我们对刚刚的shell脚本修改,用户输入一个字符串,若输入内容为空则输出“The string is null!”,否则输出“The string is not null!”,如下:

#!/bin/bash
read str
if test -z $str
then
  echo "The string is null!"
else
  echo "The string is not null!"
fi


在vi编辑器中编辑内容:

1667223706235.jpg

在Linux终端输入命令:

1667223716562.jpg


七、Shell函数


在Shell语言中,用户可自定义函数,函数的定义如下(其中return语句可以用于函数的返回值):

函数名称()
{
  命令行
  ……
  [return语句]
}


另外要注意调用时,并不是像其他语言中,以“函数名称()”的形式调用,是直接通过函数名称调用。


例1、例如,创建一个Shell脚本,其中包含一个函数,函数名称为hellofun(),其作用是用户输入用户名称,输出所输入的用户名以及“Hello linux!”,并在该脚本末尾调用该函数,如下:

#!/bin/bash
hellofun(){
  echo "please input your name:"
  read username
  echo "Your name is $username"
  echo "Hello linux!"
}
echo "The function call starts here:"
hellofun


在vi编辑器中编辑内容:

1667223769624.jpg

在Linux终端输入命令:

1667223779936.jpg

例2、例如,创建一个Shell脚本,其中包含一个函数,函数名称为Numfun(),其作用是用户输入两个数值,通过return语句返回这两个数的和,如下:

#!/bin/bash
Numfun(){
    read num1 num2
    return $(($num1+$num2))
}
Numfun
echo "The result is $? "


在vi编辑器中编辑内容:

1667223798904.jpg

在Linux终端输入命令:

1667223811544.jpg

相关文章
|
21天前
|
人工智能 分布式计算 大数据
Linux操作系统:开源力量的崛起与影响###
一场技术革命的火种,如何燎原? 本文将带您深入探索Linux操作系统的诞生背景、核心特性及其对现代科技世界的深远影响。从1991年芬兰学生Linus Torvalds的一个小众项目,到如今成为支撑全球无数服务器、超级计算机及物联网设备的基石,Linux的发展既是一部技术创新史,也是开源文化胜利的见证。通过剖析其设计哲学、安全性、灵活性等关键优势,结合实例展示Linux在云计算、大数据处理等领域的广泛应用,本文旨在揭示Linux为何能在众多操作系统中脱颖而出,以及它如何塑造了我们今天的数字生活。 ###
|
30天前
|
Ubuntu Linux Python
Tkinter错误笔记(一):tkinter.Button在linux下出现乱码
在Linux系统中,使用Tkinter库时可能会遇到中文显示乱码的问题,这通常是由于字体支持问题导致的,可以通过更换支持中文的字体来解决。
93 0
Tkinter错误笔记(一):tkinter.Button在linux下出现乱码
|
18天前
|
安全 Linux 编译器
探索Linux内核的奥秘:从零构建操作系统####
本文旨在通过深入浅出的方式,带领读者踏上一段从零开始构建简化版Linux操作系统的旅程。我们将避开复杂的技术细节,以通俗易懂的语言,逐步揭开Linux内核的神秘面纱,探讨其工作原理、核心组件及如何通过实践加深理解。这既是一次对操作系统原理的深刻洞察,也是一场激发创新思维与实践能力的冒险。 ####
|
1天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
13 9
|
4天前
|
缓存 网络协议 Linux
Linux操作系统内核
Linux操作系统内核 1、进程管理: 进程调度 进程创建与销毁 进程间通信 2、内存管理: 内存分配与回收 虚拟内存管理 缓存管理 3、驱动管理: 设备驱动程序接口 硬件抽象层 中断处理 4、文件和网络管理: 文件系统管理 网络协议栈 网络安全及防火墙管理
22 4
|
3天前
|
安全 网络协议 Linux
Linux操作系统的内核升级与优化策略####
【10月更文挑战第29天】 本文深入探讨了Linux操作系统内核升级的重要性,并详细阐述了一系列优化策略,旨在帮助系统管理员和高级用户提升系统的稳定性、安全性和性能。通过实际案例分析,我们展示了如何安全有效地进行内核升级,以及如何利用调优技术充分发挥Linux系统的潜力。 ####
18 1
|
6天前
|
物联网 Linux 云计算
Linux操作系统的演变与未来趋势####
【10月更文挑战第29天】 本文深入探讨了Linux操作系统从诞生至今的发展历程,分析了其在服务器、桌面及嵌入式系统领域的应用现状,并展望了云计算、物联网时代下Linux的未来趋势。通过回顾历史、剖析现状、预测未来,本文旨在为读者提供一个全面而深入的视角,以理解Linux在当今技术生态中的重要地位及其发展潜力。 ####
|
12天前
|
边缘计算 人工智能 运维
Linux操作系统:开源力量的崛起与影响###
一场技术革命的回顾 回溯至1991年,当Linus Torvalds宣布Linux操作系统的诞生时,世界或许并未意识到这一举措将如何深刻地改变技术领域的面貌。本文旨在探讨Linux操作系统的发展历程、核心特性、以及它如何引领了一场开源运动,重塑了软件行业的生态。从最初的个人爱好项目成长为全球最广泛采用的服务器操作系统之一,Linux的故事是技术创新与社区精神共同推动下的辉煌篇章。 ###
|
10天前
|
人工智能 安全 Linux
|
13天前
|
物联网 Linux 5G
Linux操作系统的演变与未来趋势####
本文深入探讨了Linux操作系统的发展历程,从最初的一个学生项目到如今全球最流行的开源操作系统之一。文章将分析Linux的核心优势、关键特性以及它在云计算、物联网和嵌入式系统中的应用前景。通过具体案例展示Linux如何推动技术创新,并预测其在未来技术生态中的角色。本文旨在为读者提供一个全面而深入的理解,帮助他们认识到Linux在现代计算环境中的重要性及其未来的潜力。 ####