百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

LINUX shell 基础编程介绍 linux简单的shell编程

ccwgpt 2024-12-18 14:49 24 浏览 0 评论

【十二】shell 编程

12.1 Shell 环境概述

Shell 的作用:命令解释器,“翻译官”。介于操作系统内核与用户之间,负责解释命令行。

Shell 环境的切换:

1)登录Shell

/etc/shells 文件记录了系统支持的有效登录Shell

[root@alex ~]# cat /etc/shells

2)切换Shell环境

临时切换:直接执行其他Shell程序,示例ksh、zsh等。

更改用户登录Shell:

需修改 /etc/passwd 文件中用户记录的最后一个字段

或执行:usermod -s Shell程序路径 用户名

3)查看缺省的shell

[root@alex ~]# echo $SHELL

/bin/bash

【Bash的历史命令】

1)保存用户曾经执行过的命令操作

存放位置:~/.bash_history 文件

2)查看历史命令

使用↑、↓按键逐条翻看,允许编辑并重复执行

3)执行:history

清除历史命令history -c

4)调用历史命令

!n:执行历史记录中的第n条命令

!str:执行历史记录中最近一次以“str”开头的命令【这个有用

设置历史命令能够输出的记录数,修改 HISTSIZE 参数(默认为1000条) 【这个环境变量在/etc/profile里】。

Bash的命令别名:为使用频率较高的复杂命令行设置简短的调用名称

存放位置:~/.bashrc

查看命令别名:格式:alias [别名]

如:alias sqlplus='rlwrap sqlplus'

取消已设置的命令别名 格式:unalias 别名

【注】:.bashrc会被.bash_profile调用,所以也可以将别名写到.bash_profile中。

11.2 Shell变量应用

变量的种类:

Shell变量是用来代表某个值的符号名,变量是shell传递数据的一种方法。为灵活管理,Linux系统提供特定参数,有两层意思:

变量名:使用固定的名称,由系统预设或用户定义

变量值:能够根据用户设置、依系统环境变化而变化

Shell变量的种类:

1)用户自定义变量:由用户自己定义、修改和使用

2)环境变量:由系统维护,用于设置用户的Shell工作环境,只有极少数的变量用户可以修改

3)预定义变量:Bash预定义的特殊变量,不能直接修改

4)位置变量:通过命令行给脚本传递执行参数

用户自定义变量:

定义新的变量:变量名要以英文字母或下划线开头,区分大小写

格式:变量名=变量值

查看变量的值:

格式:echo $变量名

在使用变量值时,要在变量名前加上前缀“$”。

示例①:

[root@alex ~]# abc='hello world'   字符串中有空格要使用引号
[root@alex ~]# echo $abc

hello world

[root@alex ~]# unset abc 删除变量

变量值可以作为某个长字符串中的一部分。如果它在长字符串的末尾,就可以利用直接引用形式,如果变量的值须出现在长字符串的开头或中间,避免shell把它与其他字符混在一起,则应该用花括号将变量名括起来。

示例②:

[root@alex ~]# abc=china
[root@alex ~]# echo www.$abc.com

www.china.com

[root@alex ~]# echo www.$abcalex.com

www..com

[root@alex ~]# echo www.${abc}alex.com

www.chinaalex.com

从键盘输入内容为变量赋值:

格式: read [-p “提示信息"] 变量名

结合不同的引号为变量赋值:

双引号 “ ” :允许通过$符号引用其他变量值

单引号 ‘ ’ :禁止引用其他变量值,$视为普通字符

示例③

[root@alex ~]# vi alex1.sh
#!/bin/bash
x=abc
printf "x is now $x. Enter new value: " $x
read x
echo $x

【注】:printf是一个函数

验证:

[root@alex ~]# sh alex1.sh

x is now abc. Enter new value: xyz

xyz

倒引号 ` ` :将命令执行的结果输出给变量

示例④:

[root@alex ~]# find /dev -type p

/dev/initctl

[root@alex ~]# ls -l `find /dev -type p`

prw------- 1 root root 0 01-30 13:02 /dev/initctl

【环境变量】

Shell有两类变量:临时变量和全局变量

临时变量是shell程序内部定义的,其使用范围仅限于定义它的程序,对其它程序不可见。包括:用户自定义变量、位置变量和预定义变量。

全局变量是环境变量,其值不随shell脚本的执行结束而消失。把一个Shell变量用EXPORT命令导出,就创建了环境变量。它们对于以后在该Shell下执行的所有程序都是可见的。

设置环境变量PATH:

常用命令的目录放在PATH变量中,使用频度高命令的目录排在前面;尽量避免查询大目录,如需设置,将其路径放在PATH路径的最后位置。

例:PATH=/bin:/usr/bin:/etc:/:.

位置变量(参数)

在执行Shell脚本时,可以定义最多9个位置参数,表示为$n,n为1~9之间的数字。

预定义变量:表示形式如下。

$#:命令行中位置参数的数量

$*:所有位置参数的内容

$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错

$:当前所在进程的进程号

$!:后台运行的最后一个进程号

$0:当前执行的进程/程序名

【Shell中的通配符】:

1)* 匹配任何字符串。

2)?匹配任何单个字符。

3)[...,-]匹配方括号所限定的任何一个字符【最终是方括符中某单个字符满足要求

示例:[a-d,x,y]是匹配单个字符【a、b、c、d、x、y单个字符满足要求

[!Z] 是匹配不是Z的所有单个字符

4)\ 转意符,使原字符失去其特殊的含义。

基本的算数运算:计算整数表达式的运算结果

格式:expr 变量1 运算符 变量2 ...[运算符 变量n]

expr的常用运算符:

加法运算:+

减法运算: -

乘法运算: \*

除法运算: /

求模(取余)运算: %

[root@alex ~]# a=1
[root@alex ~]# b=2
[root@alex ~]# c=`expr $a + $b` 运算符号两端要空格
[root@alex ~]# echo $c

3

[root@alex ~]# c=`expr \( $a + $b \) \* $b` 运算符号两端要空格,并且()和*都要使用转意符“\”
[root@alex ~]# echo $c

6

使用let命令格式更友好,但有些Shell不支持。

[root@alex ~]# let c=a+b
[root@alex ~]# echo $c

3

[root@alex ~]# let c=(a+b)*b
[root@alex ~]# echo $c

6

【逻辑操作符】:

1)逻辑与&&:可以把两个命令联系在一起

形式:命令1 && 命令2

功能:先运行命令1,如果成功,才运行命令2,否则不运行命令2

2)逻辑或||:命令互补

形式:命令1 || 命令2

功能:先运行命令1,不成功运行命令2,否则不运行命令2.

试比较下面的例子:

[root@alex ~]# ls -l;date;uptime;LS;ls
[root@alex ~]# ls -l&&date&&uptime&&LS&&ls
[root@alex ~]# ls -l||date||uptime||LS||ls
[root@alex ~]#LS||date||uptime||LS||ls LS不成功,补date

【成组命令】

在shell中可以使用2种方式将若干命令组合在一起,只返回一个逻辑结果。

使用花括号{}

使用圆括号()

以花括号括起来的命令可视为语法上的一条命令。成组命令的执行顺序是根据命令出现的先后次序,由左向右执行。

在使用花括号时在格式上应注意,左括号“{”后面应有一个空格;右括号“}”之前应有一个分号“;”。

在使用(){} 也可以包含若干单独占一行的命令。

[root@alex ~]# vi alex2.sh
#!/bin/bash
Parent="P"
echo Before: $Parent
{
Parent="C"
echo After: $Parent
}
echo After: $Parent

验证:

[root@alex ~]# sh alex2.sh

Before: P

After: C

After: C

把{}换成()后

[root@alex ~]# sh alex2.sh

Before: P

After: C

After: P

用圆括号括起来的成组命令是在新的子shell内执行,由于不属于同一进程,因此,在圆括号内的命令不会改变父 shell的变量值及工作目录。

12.3 编写并执行Shell脚本(一)

【Shell脚本概念】:

用途:完成特定的、较复杂的系统管理任务

格式:集中保存多条Linux命令,普通文本文件

执行方式:按照预设的顺序依次解释执行。

【脚本文件的内容】:

运行环境设置:#!/bin/bash 这句不是注释,它告诉系统后面的shell要用bash解释

注释信息:以#开始的说明性文字,可执行的Linux命令行。

【脚本的可执行权限】:

1)直接执行具有“x”权限的脚本文件

示例:./repboot.sh

2)使用指定的解释器程序执行脚本内容

示例:bash repboot.sh、sh repboot.sh

3)通过source命令(或 . )读取脚本内容执行

示例:souce repboot.sh 或 . Hello.sh

12.4 编写并执行Shell脚本(二)

12.4.1条件测试操作

【测试命令test】

用途:测试特定的表达式是否成立,当条件成立时,命令执行后的返回值为0,否则为其他数值

格式:test 条件表达式

[ 条件表达式 ]

常见的测试类型:①测试文件状态②整数值比较③字符串比较④逻辑测试

条件测试-测试文件

测试文件状态

格式:[ 操作符 文件或目录 ]

常用的测试操作符:

-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否可执行(Excute)该文件
-L:测试是否为符号连接(Link)文件

条件测试-整数值比较

整数值比较

格式:[ 整数1 操作符 整数2 ]

常用的测试操作符

-eq:等于(Equal)

-ne:不等于(Not Equal)

-gt:大于(Greater Than)

-lt:小于(Lesser Than)

-le:小于或等于(Lesser or Equal)

-ge:大于或等于(Greater or Equal)

条件测试-字符串比较

字符串比较

格式:[ 字符串1 = 字符串2 ]

[ 字符串1 != 字符串2 ]

[ -z 字符串 ]

常用的测试操作符

=:字符串内容相同

!=:字符串内容不同,! 号表示相反的意思

-z:字符串内容为空

条件测试—逻辑测试

逻辑测试

格式:[ 表达式1 ] 操作符 [ 表达式2 ] ...

常用的测试条件的逻辑操作符

!逻辑非(NOT),它放在任意逻辑表达式之前,使原来的表达式由真变假,或者由假变真。

例如:[ ! -r $1 ] 另一种写法!test -r “$1” 这句相当于说$1的内容非可读才是真

-a或&&:逻辑与,“而且”的意思,

前后两个表达式都成立时整个测试结果才为真,否则为假

例如:[ -f “$myfile” -a -r “$myfile” ] $myfile即是文件又可读才是真,否则为假

-o或||:逻辑或,“或者”的意思

操作符两边至少一个为真时,结果为真,否则结果为假

例如:[ “$a” -ge 0 -o “$b” -le 100] 假如$a=5整个结果就是真了。有一个为真就是真

()圆括号,把一个逻辑表达式括起来,使之优先得到运算,缺省下-a 的优先级高于-o,()可以改变这种优先级

12.4.2使用if条件语句

通常,if的测试部分是利用test命令或[]实现的。其实,条件测试可以利用一般命令执行成功与否来作判断。如果命令正常结束,则表示执行成功,其返回值为0,条件测试为 真,如果命令执行不成功,其返回值不等于0,条件测试就为假。如果,各命令表可以由一条或者多条命令组成,那么测试条件以其最后一条命令是否执行成功为准。

单分支:当“条件成立”时执行相应的操作

双分支:当“条件成立”、“条件不成立”时执行不同操作

多分支:相当于if语句嵌套,针对多个条件执行不同操作

示例:

[root@alex ~]# vi finduser.sh
#!/bin/bash
if [ $# -ne 1 ]
then
echo Usage: please input single username >&2
exit 1
fi
who | grep $1

【注】:>&2表示把标准输出和错误输出都定向到终端上

[root@alex ~]# bash finduser.sh root 一个位置参数

root pts/0 2016-02-01 08:52 (192.168.3.100)

[root@alex ~]# bash finduser.sh root oracle 两个位置参数时没有结果

Usage: finduser username

[root@alex ~]# echo $?

1 exit返回值是1

12.4.3使用循环语句

一)For循环

根据变量的不同取值,重复执行一组命令操作

For语句有三种格式,不同在于in的后面可以跟

For 变量 in 值表

For 变量 in 文件正则表达式

For 变量 in 命令行的位置参数

示例1:for语句使用值表。计算1 3 5 7 9的和;并且输出当前目录下的所有.sh文件。

[root@alex ~]# vi forapp1.sh
#!/bin/bash
result=0
for i in 1 3 5 7 9
do
let result=result+i
done
echo "result = $result"
###
j=1
for file in *.sh
do
echo "The ${j}th file is: $file"
j=`expr $j + 1`
done

验证

[root@alex ~]# bash forapp1.sh

示例2:for语句使用位置参数。显示所有位置参数

[root@alex ~]# vi forapp2.sh
#!/bin/bash
j=1
for i in $*
do
echo "The ${j}th parameter is: $i"
let j=j+1
done

验证

[root@alex ~]# bash forapp2.sh p1 p2

The 1 th parameter is: p1

The 2 th parameter is: p2

二)While循环语句

重复测试指定的条件,只要条件成立则反复执行对应的命令操作

示例1:whileapp1脚本:求1到10的和

[root@alex ~]# vi whileapp1.sh
#!/bin/bash
x=1
result=0
while [ $x -le 10 ]
do
let result=result+x
let x=x+1
done
echo $result

验证

[root@alex ~]# sh whileapp1.sh

55

示例2:

批量添加20个系统用户帐号, 用户名依次为“stu1”、“stu2”、……、“stu20”,这些用户的初始密码均设置为“123456”

#vi adduser.sh
#!/bin/bash
i=1
while [ $i -le 20 ]
do
useradd stu$i
echo "123456" | passwd --stdin stu$i &> /dev/null
i=`expr $i + 1`
done

应用示例2:批量删除上例中添加的20个系统用户帐号

# vi deluser.sh i
#!/bin/bash
i=1
while [ $i -le 20 ]
do
userdel -r stu$i
i=`expr $i + 1`
done

三)Until循环

until语句根据条件执行重复操作

形式:

Until 测试条件

do

命令表

done

它与while语句很相似,只是测试条件不同;当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。

示例:

1)添加一个tim用户,并授予密码

[root@alex ~]# useradd tim
[root@alex ~]# passwd tim

2)编写untilapp1.sh脚本:等待某个用户(tim)登录,每20秒确定一次

[root@alex ~]#vi untilapp1.sh
#!/bin/bash
printf "Enter username: "
read user
until who | grep $user > /dev/null
do
sleep 20
done
echo "$user have logged in"

3)执行该脚本会一直处于执行状态

[root@alex ~]#sh untilapp1.sh

Enter username: tim

4)在主控台让tim登录,则该脚本才会执行完成。

Enter username: tim

tim have logged in

12.4.4 CASE语句

CASE语句

根据变量的不同取值,分别执行不同的命令操作,Case语句允许进行多重条件选择。语法形式如下:

case 字符串 in

正则表达式1)命令

命令;;

正则表达式2)命令

命令;;

正则表达式n)命令

命令;;

esac

使用case语句应注意:

1)每个正则表达式后面可以有一条或多条命令,其最后一个命令必须以;结束,Exit命令后可以不要。

2)正则表达式中可以使用通配符。

3)如果一个正则表达式是由多个模式组成,那么各模式之间应以竖线 (|)隔开,表示各模式是“或”的关系,即只要给定字符串与其中一个模式相配,就会执行其后的命令表。

4)各正则表达式应是唯一的,不应重复出现。并且要合理安排正则表达式的出现顺序。例如,不应将“*”作为头一个正则表达式。因为与任何字符串匹配,它若第一个出现,就不会再检查其他表达式了。

5)Case的退出(返回)值是整个结构中最后执行的那个命令。若没有执行任何命令,则退出值为零。

示例:

[root@alex ~]# vi caseapp.sh
#!/bin/bash
name=`basename $0 .sh`
case $1 in
s|start)
echo "start..."
;;
stop)
echo "stop..."
;;
reload)
echo "reload..."
;;
*)
echo "Usage: $name [start|stop|reload]"
exit 1
;;
esac
exit 0

【注】:basename这里就是取得不带路径的执行的shell脚本的名称, 扩展名.sh也会去掉。

例如:# basename /root/test/finduser.sh .sh

finduser

验证

[root@alex ~]# sh caseapp.sh s

start...

[root@alex ~]# sh caseapp.sh start

start...

[root@alex ~]# sh caseapp.sh stop

Stop...

[root@alex ~]# echo $?

0

[root@alex ~]# sh caseapp.sh abc

Usage: caseapp [start|stop|reload]

[root@alex ~]# sh caseapp.sh

Usage: caseapp [start|stop|reload]

[root@alex ~]# echo $?

1

SHIFT 语句:

位置参数最多不能超过9个,即$1~$9。如果实际给定的 命令行参数多于9个,就需要用shift命令移动位置参数。每执行一次 shift 命令,就把位置参数向左移一位,新的$1的值是原来$2的值,新 $2 是原来$3的值,依次类推。

Shift 命令不能把$0移走。Shift 命令可以带有一个整体作为参数。如果没有带参数默认是1

示例:

[root@alex ~]# vi shiftapp1.sh
#!/bin/bash
#loop=0
while [ $# -ne 0 ]
do
echo $1
done

# 修改权限,让其可执行

[root@alex ~]# chmod u+x shiftapp1.sh

# 执行

[root@alex ~]# ./shiftapp1.sh p1 p2 p3

结果:死循环,而不是将所有的参数输出后结束。

#!/bin/bash
#loop=0
while [ $# -ne 0 ]
do echo $1
shift
done
[root@alex ~]# ./myapp1.sh p1 p2 p3

p1

p2

p3...

如果改成shift 2如何

【循环控制语句】:break语句

在for、while、until等循环语句中,用于跳出当前所在的循环体,执行循环体后的语句

continue

在for、while、until等循环语句中,用于跳过循环体内余下的语句,重新判断条件以便执行下一次循环

Shell函数应用:

在编写Shell脚本程序时,将一些需要重复使用的命令操作,定义为公共使用的语句块,即可称为函数,合理使用Shell函数,可以使脚本内容更加简洁,增强程序的易读性,提高执行效率。

应用示例:

在脚本中定义一个加法函数,名叫adder,用于计算2个整数的求和

调用该函数计算(12+34)、(56+789)的和

[root@alex ~]# vi addderfun.sh
#!/bin/bash
adder() {
echo `expr $1 + $2`
}
adder 12 34
adder 56 789

验证

[root@alex ~]# sh adderfun.sh

46

845



the end !!!

@jackman 共筑美好!

相关推荐

迈向群体智能 | 智源发布首个跨本体具身大小脑协作框架

允中发自凹非寺量子位|公众号QbitAI3月29日,智源研究院在2025中关村论坛“未来人工智能先锋论坛”上发布首个跨本体具身大小脑协作框架RoboOS与开源具身大脑RoboBrain,可实...

大模型对接微信个人号,极空间部署AstrBot机器人,万事不求百度

「亲爱的粉丝朋友们好啊!今天熊猫又来介绍好玩有趣的Docker项目了,喜欢的记得点个关注哦!」引言前两天熊猫发过一篇关于如何在极空间部署AstrBot并对接QQ消息平台的文章,不过其实QQ现在已经很少...

Seata,让分布式事务不再是难题!实战分享带你领略Seata的魅力!

终身学习、乐于分享、共同成长!前言Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的...

常见分布式事务解决方案(分布式事务解决的问题)

1.两阶段提交(2PC)原理:分为准备阶段(协调者询问参与者是否可提交)和提交阶段(协调者根据参与者反馈决定提交或回滚)。优点:强一致性,适用于数据库层(如XA协议)。缺点:同步阻塞:所有参与者阻塞...

分布式事务:从崩溃到高可用,程序员必须掌握的实战方案!

“支付成功,但订单状态未更新!”、“库存扣减后,交易却回滚了!”——如果你在分布式系统中踩过这些“天坑”,这篇文章就是你的救命稻草!本文将手把手拆解分布式事务的核心痛点和6大主流解决方案,用代码实战+...

谈谈对分布式事务的一点理解和解决方案

分布式事务首先,做系统拆分的时候几乎都会遇到分布式事务的问题,一个仿真的案例如下:项目初期,由于用户体量不大,订单模块和钱包模块共库共应用(大war包时代),模块调用可以简化为本地事务操作,这样做只要...

一篇教你通过Seata解决分布式事务问题

1 Seata介绍Seata是由阿里中间件团队发起的开源分布式事务框架项目,依赖支持本地ACID事务的关系型数据库,可以高效并且对业务0侵入的方式解决微服务场景下面临的分布式事务问题,目前提供AT...

Seata分布式事务详解(原理流程及4种模式)

Seata分布式事务是SpringCloudAlibaba的核心组件,也是构建分布式的基石,下面我就全面来详解Seata@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合...

分布式事务最终一致性解决方案有哪些?MQ、TCC、saga如何实现?

JTA方案适用于单体架构多数据源时实现分布式事务,但对于微服务间的分布式事务就无能为力了,我们需要使用其他的方案实现分布式事务。1、本地消息表本地消息表的核心思想是将分布式事务拆分成本地事务进行处理...

彻底掌握分布式事务2PC、3PC模型(分布式事务视频教程)

原文:https://mp.weixin.qq.com/s/_zhntxv07GEz9ktAKuj70Q作者:马龙台工作中使用最多的是本地事务,但是在对单一项目拆分为SOA、微服务之后,就会牵扯出分...

Seata分布式事务框架关于Annotation的SAGA模式分析

SAGAAnnotation是ApacheSeata版本2.3.0中引入的功能,它提供了一种使用Java注解而不是传统的JSON配置或编程API来实现SAGA事务模式的声明...

分布式事务,原理简单,写起来全是坑

今天我们就一起来看下另一种模式,XA模式!其实我觉得seata中的四种不同的分布式事务模式,学完AT、TCC以及XA就够了,Saga不好玩,而且长事务本身就有很多问题,也不推荐使用。S...

内存空间节约利器redis的bitmap(位图)应用场景有哪些你知道吗

在前面我们分享过一次Redis常用数据结构和使用场景,文章对Redis基本使用做了一个简单的API说明,但是对于其中String类型中的bitmap(位图)我们需要重点说明一下,因为他的作用真的不容忽...

分布式事务原理详解(图文全面总结)

分布式事务是非常核心的分布式系统,也是大厂经常考察对象,下面我就重点详解分布式事务及原理实现@mikechen本文作者:陈睿|mikechen文章来源:mikechen.cc分布式事务分布式事务指的是...

大家平时天天说的分布式系统到底是什么东西?

目录从单块系统说起团队越来越大,业务越来越复杂分布式出现:庞大系统分而治之分布式系统所带来的技术问题一句话总结:什么是分布式系统设计和开发经验补充说明:中间件系统及大数据系统前言现在有很多Java技术...

取消回复欢迎 发表评论: