首页 > 系统相关 >linux之shell

linux之shell

时间:2024-09-07 10:54:04浏览次数:12  
标签:shell ## echo sh linux root localhost

Shell编程

shell简介

shell的作用

1.解释执行用户输入的程序或者指令

2.用户输入一条指令,shell解释一条

3.键盘输入指令,Linux给与响应 ----- 这个过程称之为交互式响应流程

shell是一块包裹着系统核心的壳,处于操作系统的最外层,与用户直接对话,shell可以把用户的输入,解释给操作系统, 然后处理操作系统的输出结果,输出到屏幕给用户看到结果。 ---- 翻译官

指令的工作流程

shell的分类和切换

shell解释器的版本

查看当前使用解释器版本

shell的修改
vim /etc/passwd

shell脚本

1. 当命令或者程序语句书写在文件中,我们去执行文件,读取其中的代码 ---- 这个文件就称之为 shell脚本
2. 在shell脚本中定义多条linux的指令,以及 选择分支,循环,函数,数组..... 然后将linux命令一次性执行完毕。
    这种执行脚本文件的方式 ------ 非交互式
    程序员在客户端敲指令,然后回车出结果 ------ 交互式
3. shell的脚本规则
    在linux系统中 shell脚本(shell程序) 通常由 vim 编辑 bash shell 指令 , 逻辑控制语言 , 注释等组成

第一个shell程序

方式一
1.编辑文件
    vim hello.sh
    文件内容: echo "HelloWorld
2.解释文件
    /bin/bash hello.sh # 自行指定文件的shell解释器版本 可以省略 (shebang)
    或者
    bash hello.sh
方式二
编辑文件
    vim hello.sh
    文件内容: echo "HelloWorld
1.给文件增加执行权限
    chmod +x hello.sh
2.执行文件 # 文件要提供相对或者绝对路径
[root@localhost localhost]# /localhost/hello.sh
HelloWorld
方式三
编辑文件
    vim hello.sh
    文件内容: echo "HelloWorld
    
[root@localhost localhost]# source hello.sh
HelloWorld
    等价于
[root@localhost localhost]# . hello.sh
HelloWorld
# source 文件.sh 等价于 . 文件.sh
方式四
1. 编辑文件
vim world.sh
​
#! /bin/bash
echo "Hello正统方式"
2. 执行文件
可以使用以上三种方式
Shebang (释伴)
文件内容 #! ------- shebang的两个符号
​
Shebang通常出现在类Unix系统的脚本中第一行,作为前两个字符。在Shebang之后,可以有一个或数个空白字符,后接解释器的绝对路径,用于指明执行这个脚本文件的解释器。在直接调用脚本时,系统的程序载入器会分析 Shebang 后的内容,将这些内容作为解释器指令,并调用该指令,将载有 Shebang 的文件路径作为该解释器的参数,执行脚本,从而使得脚本文件的调用方式与普通的可执行文件类似。例如,以指令#!/bin/sh开头的文件,在执行时会实际调用 /bin/sh 程序(通常是 Bourne shell 或兼容的 shell,例如 bash、dash 等)来执行。

注意

1. 如果没有指定 shebang 脚本执行的时候 默认使用的是 系统当前的shell解释器 $SHELL
2. 如果 #! 指定了解释器 但是没有执行该文件的权限 报错
3. 解释器的选择存在优先级
    1. 运行脚本文件时 自行指定的 解释器 (无论写没写 shebang)
    2. 若脚本文件中填充了 shebang 书写指令时,借助系统的shell解释器 但是shebang解析以后优先启用
    3. 若脚本中未填充 shebang 且运行文件时未书写 解释器 使用 系统的解释器 $SHELL

脚本注释

1. 在shell脚本中 "#" 后面的内容就代表注释
2. 注释提供给开发者查看的,系统会忽略注释
3. 脚本注释的语法
    # 注释内容
    举例:
    # 向界面输出HelloWorld
    echo "HelloWorld"

脚本语言

shell脚本语言属于一种弱类型语言 : 无需声明变量类型 直接定义使用
例如: name="小黑" age=20 score=80.0
​
强类型:
   int   double   char  boolean 
    int a = 10 √
    a = 15    √
    a = "shuaihui"  ×
​
弱类型:
   var  
   var  v = 10
   v = 15 √
   v = "zhangsan"  √

shell会保留会话中用户曾提交的命令

# 查看历史命令记录 [包含文件中和内存中的历史记录]
history
# 查看文件中的历史指令记录 若误删了内存中的历史指令,可以借助 history -r 文件 进行恢复
[root@localhost localhost]# vim /root/.bash_histor
# 查看所有历史命令记录
history
列出历史命令以后 可以 选中 历史命令的编号 再次执行
# !历史命令的编号
# 查看前10条历史命令记录
history 10
history命令参数详解
-c 清空内存中历史命令
-r 可以从文件中恢复历史命令

shell变量

变量概念

变量是计算机内存存储数据的地方。是一种数据标记(房间号,标记了客人[数据]的位置) 数据存储在内存空间, 通过调用对应的变量名,即可获取对应的值。[变量名与值之间,包括等号 不能有空格]

# 定义一个变量
变量名=值 # shell规范中 所有的值都是字符串
例如:
name="小黑"
age="20"
score=1.2
#定义一个变量的案例
[root@localhost ~]# name="小黑"
[root@localhost ~]# echo "HelloWorld"
HelloWorld
[root@localhost ~]# echo HelloWorld
HelloWorld
[root@localhost ~]# echo $name
小黑
#获取变量的值
完整写法 ${变量名}
简化写法 $变量名
# 若变量名[在重合的作用域内]重复
name="小黑"
name="小白" # 指令执行,相当于修改变量name中保存的值
echo $name # 小白

变量名的规则

1. 名称定义要做到望文生义,要按照规则来 不能使用保留字,关键字
2. 只能包含数字,字母,下划线(_)
3. 不能以数字开头
4. 不能使用标点符号
5. 变量名要严格区分大小写
# 变量名严格区分大小写
[root@localhost ~]# name="小黑"
[root@localhost ~]# Name="小白"
[root@localhost ~]# echo $Name
小白
[root@localhost ~]# echo $name
小黑
# 以下命名不符合规则
change_123 OK!
change@123 error!
1change_123 error!
_change123 ok!
test_insert_student_info ok!

变量的分类

1. 本地变量
2. 全局变量
3. 局部变量
4. 特殊变量
5. 自定义的变量
# 安装软件 psmisc 查看父子 shell
yum -y install psmisc
# pstree
查看父子shell的关系

本地变量
在当前shell中有效(切换子shell , 子 shell 无法获取定义的变量)
注意:
    1. 父 shell 进 子 shell 运行 携带 bash或者sh的指令即可
    2. 子 shell 回 父 shell exit # 通过pstree 查看父子shell关系 以及当前所处的 shell

环境变量
环境变量也称之为全局变量.针对当前的shell以及任意的子shell 都有效。 环境变量也分为 自定义、内置。

每个用户都有自己的环境变量(全局变量)配置文件 ~/.bash_profile ~/.bashrc(个人) 优先加载并读取变量, 以个人的优先生效

 

2.全局配置文件 /etc/profile /etc/bashrc 但 系统建议最好创建在 /etc/profile.d/ 而非修改主文件 修改全局配 置文件 影响所有登录系统的用户 ---------- root有权修改

3.环境变量一般是指 使用 export内置命令导出的变量 , 用于定义shell的运行环境 保证shell命令的正确执行 shell设置登录的用户名 PATH路径 文件系统.....

4.环境变量可以在命令行中临时创建, 但是当用户退出终端时 命令丢失 在配置文件中定义,永久有效

检查系统环境变量(全局变量)
set # 输出所有变量 包含全局变量、局部变量
env # 只显示全局变量
declare # 输出所有变量 等同于 set
export # 显示和设置环境相关的变量值(等同于全局)
撤销系统环境变量
unset 变量名 # 删除变量或者函数
例如:
    unset age;
设置只读变量
readonly # 在shell结束前,只允许获取变量的值 不允许修改
[root@localhost ~]# readonly age=20
[root@localhost ~]# echo $age
20
[root@localhost ~]# age=30
bash: age: 只读变量
设置临时的全局变量
export age1=30
环境变量初始化与加载顺序

局部变量
定义在函数内部的变量,只在函数内部有效
特殊变量

shell的特殊变量,用在比如 脚本 , 函数传递参数时使用

殊变量 $0 $1 $2的案例演示
结果为 ./special.sh --- 小黑 ---- abc
########################################
特殊变量$#的案例演示
获取参数的总个数
参数的总个数为: 5
#########################################
演示 $*的案例
结果为: 小黑 abc 小白 def 小兰
########################################
演示 $@ 的案例
结果为: 小黑 abc 小白 def 小兰
[root@localhost localhost]# cat special.sh
#! /bin/bash
echo '特殊变量 $0 $1 $2的案例演示'
echo '结果为' $0 '---' $1 '----' $2
echo '########################################'
echo '特殊变量$#的案例演示'
echo '获取参数的总个数'
echo '参数的总个数为:' $#
echo '#########################################'
echo '演示 $*的案例'
echo '结果为:' $*
echo '########################################'
echo '演示 $@ 的案例'
echo '结果为:' $@
# $* 和 $@ 的区别
[root@localhost localhost]# ./special2.sh 小黑 123 小白 456 小兰
演示 "$*" 的用法
小黑 123 小白 456 小兰
---------------------------------------
演示 "$@" 的用法
小黑
123
小白
456
小兰
[root@localhost localhost]# cat special2.sh
#! /bin/bash
echo '演示 "$*" 的用法'
for i in "$*"
do
    echo "$i"
done
echo '---------------------------------------'
echo '演示 "$@" 的用法'
for a in "$@"
do
    echo "$a"
done
$? 获取上一次指令执行的状态返回值 0 正确 非0失败可以自定义 exit 120  执行失败时echo? 就打印 120
$$ 当前 shell脚本的 进程号
$! 上一次后台进程的PID
$_ 获取上一次的命令执行时传递的最后一个参数
## 1. 演示$?
[root@localhost localhost]# ll /etc # 正确指令
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# ll /etcc # 路径错误
ls: 无法访问/etcc: 没有那个文件或目录
[root@localhost localhost]# echo $?     # 上个命令执行失败,输出2
## 2. 演示 $$
[root@localhost localhost]# echo $$     # 执行失败时,输出的状态码
## 3. 演示 $_
[root@localhost localhost]# sh special.sh 小黑 小白
特殊变量 $0 $1 $2的案例演示
结果为 special.sh --- 小黑 ---- 小白
########################################
特殊变量$#的案例演示
获取参数的总个数
参数的总个数为: 2
#########################################
演示 $*的案例
结果为: 小黑 小白
########################################
演示 $@ 的案例
结果为: 小黑 小白
[root@localhost localhost]# echo $_     # 获取上一个命令的最后一个参数
小白

脚本控制返回值

[root@localhost localhost]# ./t1.sh 123 456 789
你必须传递两个参数
刚刚好传递了两个参数
[root@localhost localhost]# vim t1.sh
[root@localhost localhost]# ./t1.sh 123 456 789
你必须传递两个参数
[root@localhost localhost]# ./t1.sh 123 456
刚刚好传递了两个参数
[root@localhost localhost]# cat t1.sh
#! /bin/bash
[ $# -ne 2 ] && {
    echo "你必须传递两个参数"
    exit 119 # 终止程序运行,且返回119状态码以后 提供给当前shell的 $? 变量
}
echo "刚刚好传递了两个参数"
内置的shell命令
1. echo 打印输出内容
参数:
-n 不换行输出
-e 解析字符串中的特殊符号
##echo 案例演示
[root@localhost localhost]# echo 你瘦了;echo 你多吃点
你瘦了
你多吃点
[root@localhost localhost]# echo -n 你瘦了;echo 你多吃点
你瘦了你多吃点
[root@localhost localhost]# echo "你人还挺好"
你人还挺好
[root@localhost localhost]# echo "你人\n还挺好"
你人\n还挺好
[root@localhost localhost]# echo -e "你人\n还挺好"
你人
还挺好
2.eval 相当于把第二个指令当做参数传递给 eval
## eval案例演示
[root@localhost localhost]# ls < /etc
demo.sh hello.sh special2.sh special.sh t1.sh world.sh
[root@localhost localhost]# eval ls;cd /etc
demo.sh hello.sh special2.sh special.sh t1.sh world.sh
3.exec 不创建子进程 执行后续命令 且执行完毕后 自动 exit
## exec案例演示
[root@localhost localhost]# exec date
等价于
[root@localhost localhost]# date
[root@localhost localhost]# exit

字符串操作

字符串截取

# 从开头删除匹配最短 pcabcabc [p*c] -----> abcabc
## 从开头删除匹配最长 pab6666666c [p*c] -----> 空
% 从结尾删除匹配最短 pcabcapbc [p*c] -----> pcabca
%% 从结尾匹配删除最长 pcabcapbc [p*c] ----> 空
替换
${变量名/匹配模式/新值} 用新值替换第一个满足匹配模式的子字符串
${变量名//匹配模式/新值} 用新值代替所有满足匹配模式的子字符串
// 指定匹配内容截取
a*c 匹配开头是 a 中间任意个字符 结尾是 c 的字符串 ac abc a123456c
## 1
. 单# 与 双 ## 演示
## 2. ${#变量}
统计变量中保存字符串的长度
[root@localhost ~]# str1="changge123456changge"
[root@localhost ~]# echo $str1
changge123456changge
[root@localhost ~]# echo ${#str1}
20
## 3. ${变量名:start}
从 start下标开始(包含start) 截取字符串 ----------- 下标从0开始,依次递增
[root@localhost ~]# str1="changge123456changge"
[root@localhost ~]# echo $str1
[root@localhost ~]# echo ${str1:2}
angge123456changge
## 4. ${变量名:start:length}
提取start之后的length个字符,包含start
[root@localhost ~]# echo ${str1:2:5}
angge
## 5. ${变量名#关键词}
从头开始,删除匹配最短的第一个关键词
[root@localhost ~]# echo ${str1#ch}
angge123456changge
[root@localhost ~]# str3="234511654321"
[root@localhost ~]# echo ${str3#2*4}        # 匹配最短的2-4
511654321
## 6. ${变量名##关键词}
[root@localhost ~]# str3="234511654321"
[root@localhost ~]# echo ${str3##2*4}       # 匹配最长的2-4
321
## 7. ${变量名%关键字}
从结尾开始删除匹配最短
[root@localhost ~]# echo ${str2}
1234511654321
[root@localhost ~]# echo ${str2%1*4}
1234511654321
[root@localhost ~]# echo ${str2%4*1}
123451165
## 8. ${变量名%%关键字}
从结尾开始删除匹配最长
[root@localhost ~]# echo ${str2%%4*1}
123
## 9. ${变量名/匹配模式/str}
使用str替换第一个字符串中满足匹配模式的内容
[root@localhost ~]# str4="1234568812345688456"
[root@localhost ~]# echo ${str4}
1234568812345688456
[root@localhost ~]# echo ${str4/88/aa}
123456aa12345688456
[root@localhost ~]# echo ${str4//88/aa}
123456aa123456aa456

统计字符串长度

[root@localhost ~]# echo $str4
1234568812345688456
## 1. 办法1: ${#变量名} ---- 效率最高
[root@localhost ~]# echo ${#str4}
19
[root@localhost ~]# time echo ${#str4} # 获取指令的执行时长
19
real 0m0.000s
user 0m0.000s
sys 0m0.000s
## 2. 办法2:
[root@localhost ~]# echo $str4 | wc -L
19
[root@localhost ~]# time echo $str4 | wc -L
19
real 0m0.002s
user 0m0.000s
sys 0m0.001s
## 3. 办法3 利用 数值计算expr
[root@localhost ~]# time expr length "${str4}"
19
real 0m0.001s
user 0m0.001s
sys 0m0.000s
# 4. 办法4: awk统计长度 length函数
[root@localhost ~]# time echo $str4 | awk '{print length($0)}'
19
real 0m0.002s
user 0m0.000s
sys 0m0.001s

shell扩展变量

## 扩展变量1
result=${param:-word}
如果param变量中保存的值为空,返回word,赋值给result
[root@localhost ~]# param="123456789"
[root@localhost ~]# result=${param:-666666}
[root@localhost ~]# echo $result
123456789
[root@localhost ~]# result=${param2:-666666}
[root@localhost ~]# echo $result
666666
[root@localhost ~]# echo $param2
[root@localhost ~]#
## 扩展变量2
result=${param:=word}
如果param变量中保存的值为空 则 word 赋值给 param 同时 返回给 result
[root@localhost ~]# echo $param2
[root@localhost ~]# result=${param2:=888888}
[root@localhost ~]# echo $result
888888
[root@localhost ~]# echo $param2
888888
## 扩展变量3
${param:?word}
如果param变量中没有值,将word当做标准错误输出 否则 输出 param的变量值
#用于设置变量为空时导致的错误,返回错误信息
## 扩展变量4
${param:+word}
如果param变量中没有值,什么都不做 如果有值 将 word返回

父子shell

pstree 查看父子shell的关系

 

ps -ef

-f 展示 UID PID PPID

-e 列处所有进程信息

ps -ef --forest

 

shell的进程列表 : 需要使用 () 将这组指令包括进去 ------- 这种方式就称之为 进程列表

(cd ~;ls;pwd;echo "小黑";.........) --- 这些指令是交给多个 子 shell执行

检测是否在子shell环境中

linux默认的有关shell的变量
## BASH_SUBSHELL
该变量的值有特点: 如果是 0 就处于当前shell环境中执行 否则 就是开辟了子shell去执行
[root@localhost ~]# (cd ~;ls;pwd;echo "小黑黑");echo $BASH_SUBSHELL
anaconda-ks.cfg localhost cronDemo.sh
/root
小黑黑
0
## 一个父shell下开启多个平行的子shell去执行指令执行以后,自行回到父shel

子shell嵌套运行

[root@localhost ~]# (pwd;(pwd;(echo $BASH_SUBSHELL)))
/root
/root
3

数学运算

算数运算符

+ - 加法减法
* / % 乘法 取商 取模(取余) 5除以2 商是2 余数(模)是 1 5/2-----2 5%2-----1
** 幂运算 5的2次方: 5**2-------25 5的3次方: 5**3------125
++ -- 操作数自身增加或者减少1 a++ ++a
&& || ! 逻辑与 逻辑或 取反
< > <= >= == =(对于字符串也相当于比较) != 小于 大于 小于等于 大于等于 等于 不等于
= += -= *= /= %= 赋值运算符 num=1 num+=1 num*=3

算数运算命令

(()) 经常用于整数运算 效率很高
let 用于整数运算 等同于 (())
expr 可用于整数运算,还有其他额外功能
bc [需要先安装] Linux下的一个计算器程序(适合整数以及小数运算)
$[] 用于整数运算
运算操作符与运算命令
((i=i+1)) 运算后赋值。将 i+1 的运算结果赋值给变量 i 若要打印 echo $((i=i+1))
i=$((i+1)) 将表达式运算后的结果赋值给 i
((8>7&&5==5)) 可以进行比较操作 还可以加入逻辑与 逻辑或 经常用于条件判断
echo $((2+1)) 打印输出运算表达式的结果 需要在 (())前添加 $
## 1.有关逻辑运算 真(1) 假(0)
[root@localhost ~]# echo $((8>7))
1
[root@localhost ~]# echo $((6>7))
0
## 2. 逻辑运算符的演示 && || ! # !的案例?
[root@localhost ~]# echo $((6>7&&3>4))
0
[root@localhost ~]# echo $((6>7&&3<4))
0
[root@localhost ~]# echo $((7>6&&5>4))
1
[root@localhost ~]# echo $[!((8>7))]
0
​
## 3.算数运算
[root@localhost ~]# echo $((3+4))
7
[root@localhost ~]# echo $((3-4))
-1
[root@localhost ~]# echo $((3*4))
12
[root@localhost ~]# echo $((4/3))
1
[root@localhost ~]# echo $((4%3))
1
[root@localhost ~]# echo $((3/4))
0
[root@localhost ~]# echo $((3%4))
3
[root@localhost ~]# echo $((15000/22/8))
85
[root@localhost ~]# echo $((15000/22/8+2))
87
[root@localhost ~]# echo $((2+15000/22/8+2))
89
​
# 4. 幂运算
[root@localhost ~]# echo $((5**2))
25
[root@localhost ~]# echo $((5**3))
125
[root@localhost ~]# echo $((5**4))
625
​
## 5. 给变量赋值
[root@localhost ~]# num=100
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# ((num*3))
[root@localhost ~]# echo $num
100
[root@localhost ~]# ((num=num*3))
[root@localhost ~]# echo $num
300
[root@localhost ~]# sum=100
[root@localhost ~]# echo $((sum=sum*3))
300
[root@localhost ~]# add=10
[root@localhost ~]# echo $((add+=100))
110
[root@localhost ~]# echo $add
110

用于数值计算的命令

[root@localhost ~]# a=10
[root@localhost ~]# ((a=2+2**3-4%3+a))
[root@localhost ~]# echo $a
19
[root@localhost ~]# b=((2+2**3-4/4+4**2)) # 错误
-bash: 未预期的符号 `(' 附近有语法错误
[root@localhost ~]# b=$((2+2**3-4/4+4**2))
[root@localhost ~]# echo $b
25
[root@localhost ~]# ((b=2+2**3-4/4+4**2))
[root@localhost ~]# echo $b
25
注意:
(()) 只能对整数进行运算 -----> bc
[root@localhost ~]# ((c=1+100+2**3+1.2))
-bash: ((: c=1+100+2**3+1.2: 语法错误: 无效的算术运算符 (错误符号是 ".2")

特殊符号运算

++ 变量自增1
-- 变量自减1
a++ 先对变量a操作,然后再让a自增1
++a 先让a自增1,然后再复制给a
[root@localhost ~]# a=5
[root@localhost ~]# echo $((++a))
6
[root@localhost ~]# echo $a
6
[root@localhost ~]# b=5
[root@localhost ~]# echo $((b++))
5
[root@localhost ~]# echo $b
6
[root@localhost ~]# c=5
[root@localhost ~]# echo $((c--))
5
[root@localhost ~]# echo $c
4
[root@localhost ~]# d=5
[root@localhost ~]# echo $((--d))
4
[root@localhost ~]# echo $d
4

let的使用

## let 对变量的数值运算
[root@localhost ~]# num=5
[root@localhost ~]# let num=num+4
[root@localhost ~]# echo $num
9
[root@localhost ~]# let num+=1.2
-bash: let: num+=1.2: 语法错误: 无效的算术运算符 (错误符号是 ".2")
​

expr

## expr命令不太好用,基于空格传入参数 但是在shell中一些字符具备特殊含义
[root@localhost ~]# expr 5+3
5+3
[root@localhost ~]# echo $((5+3))
8
[root@localhost ~]# expr 5 + 3
8
[root@localhost ~]# expr 5 * 3
expr: 语法错误
[root@localhost ~]# expr 5 \* 3
15
[root@localhost ~]# expr 5 \+ 3
8
[root@localhost ~]# expr 5 % 3
2
[root@localhost ~]# expr 5 \% 3
2
## 注意 : 数值与运算符号之间需要加空格 运算符很容易识别失败 需要转义
[root@localhost ~]# expr 5 + 3 + 4 \* 2 -4
expr: 语法错误
[root@localhost ~]# expr 5 + 3 + 4 \* 2 - 4
12
[root@localhost ~]# expr 5 \> 6
0
[root@localhost ~]# expr 8 \> 6
1

expr的内置函数

length函数
## 案例
[root@localhost ~]# expr length 123456789
9
[root@localhost ~]# expr length 123456789
9
[root@localhost ~]# size="123456789"
[root@localhost ~]# expr length $size
9
[root@localhost ~]# size="123456789 "
[root@localhost ~]# expr length $size
9

expr的模式匹配

expr命令也支持模式匹配功能
两个特殊符号
: 冒号用于计算字符串的字符数量 gaosc 5个字符
.* 任意的字符串重复0次或多次
最后的模式 支持自定义
## 语法
expr 字符串 ":" ".*"
## 根据指定的字符获取 包括字符在内 字符及字符之前的 数量
[root@localhost ~]# expr test.jpg ":" ".*"
8
[root@localhost ~]# expr test.jpg ":" ".*j"
6
[root@localhost ~]# expr test.jpg ":" ".*p"
7
[root@localhost ~]# expr yc.png ":" ".*\.png"
6
[root@localhost ~]# expr yc.png ":" ".*\.jpg"
0
[root@localhost ~]# expr yc.jptg ":" ".*\.jpg"
0
[root@localhost ~]# expr yc.jpggggggggggggggggggg ":" ".*\.jpg"
6

bc命令

# 1. 安装 bc 软件
yum -y install bc
# 2.使用计算器
bc

bc命令结合管道符来计算
[root@localhost ~]# echo "4*4"
4*4
[root@localhost ~]# echo "4*4" | bc
16
[root@localhost ~]# echo "4.2*4" | bc
16.8
[root@localhost ~]# echo $num*1.2 | bc
6.0
[root@localhost ~]# result=`echo $num*1.2 | bc`
[root@localhost ~]# echo $result
6.0
​
bc应用的案例
## 计算1~1000的和
数学公式
1+2+3+4+5+6+...+999+1000
## 1.先想办法获取这些操作数
[root@localhost ~]# echo {1..1000}
## 2.将数字之间的空格替换为 +
[root@localhost ~]# echo {1..1000} | tr " " "+"
## 3.将上一步处理以后的字符串交给 bc 进行运算
[root@localhost ~]# echo {1..1000} | tr " " "+" | bc
500500
[root@localhost ~]# seq -s "+" 1000 | bc
500500
[root@localhost ~]# echo $((`seq -s "+" 1000`))
500500
###补充
seq 数字 # 打印1 2 3 4 5 ... 数字 数字之间分隔符默认为换行
seq -s 数字连接符 数字 # 指定连接符连接 1 2 3 4.... 数字
### 例如
seq -s "+" 10
输出 1+2+3+4+5+6+7+8+9+10
[root@localhost ~]# seq -s " + " 1000 | xargs expr
500500

read指令

可以在程序运行过程中,程序员输入数据

## 从标准输入中读取数据并赋值给指定变量
# 语法 read 变量名
[root@localhost ~]# read var
123 # 借助键盘标注输入设备,录入数据以后 保存在 var变量中
[root@localhost ~]# echo $var
123
## 从标准输入中输入多个值(用空格间隔),回车输入结束 第一个值给变量1 后续所有的值给变量2
## 语法 read 变量1 变量2
[root@localhost ~]# read first last
123 456 789 000 111 222
[root@localhost ~]# echo $first
123 # first保存第一个值
[root@localhost ~]# echo $last
456 789 000 111 222 # 其余的值存入 last变量中
[root@localhost ~]# read a b c # a b两个变量中各存一个值 其余赋值给 c
123 456 789 123
[root@localhost ~]# echo $a
123
[root@localhost ~]# echo $b
456
[root@localhost ~]# echo $c
789 123
## 若read后未指定变量名,则数据赋值给变量 REPLY
[root@localhost ~]# read
123
[root@localhost ~]# echo $REPLY
123
## 把多个值存入一个变量中
语法:
read -a 变量
[root@localhost ~]# read -a array
123 456 789 456 789 123 000
[root@localhost ~]# echo ${array[0]}
123
[root@localhost ~]# echo ${array[1]}
456
[root@localhost ~]# echo ${array[6]}
000
[root@localhost ~]# echo ${array[@]}
123 456 789 456 789 123 000
​
## 限定输入读取的时长
语法:
read -t 时间 变量
## 测试数据
read.sh
#!/bin/bash
echo "请在五秒内完成密码录入并回车,请输入密码:"
read -t 5 passwd ## 在5秒内完成信息录入并回车 否则数据不会保存
echo "--------------------------"
echo "您输入的密码为:"$passwd
## 操作界面
[root@localhost localhost]# ./read.sh
请在五秒内完成密码录入并回车,请输入密码:
123456
--------------------------
您输入的密码为:123456
​
## 允许输入反斜杠
语法:
read -r 变量名
[root@localhost localhost]# read var
123 \
>
[root@localhost localhost]# read -r var
123 \ 123 \ 123
​
## 默认是 回车键代表结束输入
read -d "符号" 变量名
[root@localhost localhost]# read -d ":" var
123 :[root@localhost localhost]# read -d ":" var
123
## 此时回车结束符被 冒号 覆盖
:[root@localhost localhost]#
## 从标准输入中读取两个字符 并存入变量 不需要按回车读取结束
语法:
read -n 2 变量名
[root@localhost localhost]# read -n 2 var
12[root@localhost localhost]#

shell测试

shell测试语法参数

得出一个指令真假的概念(文件是否存在,文件夹是否存在.......)

条件测试语法说明
test 测试表达式test 与 测试表达式之间至少一个空格
[ 测试表达式 ]用法与test一致 但是测试表达式左右两侧都必须有空格
[[ 测试表达式 ]]用法要求与 [] 一致 双中括号是对单中括号的补充
(( 测试表达式 ))测试表达式两端不需要空格

test条件测试

test命令评估表达式,它的结果是真,还是假 如果条件为真 那么 命令执行状态码的结果就是 0 若条件为假 执行 状态码不为0 执行状态码获取 $?

if(条件为真){
    exit 0 ; 执行状态码为0
}else{
    exit 1; 条件为假 执行状态码不为0
}
文件类型参数
参数介绍:
    -e : 判断指定文件(文件夹)是否存在 存在即为真 不存在 为假
[root@localhost localhost]# test -e /a.txt
### 当结果为真,也就是文件存在 命令执行状态码是 0
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test -e /d.txt
### 当结果为假,也就是文件不存在 命令执行状态码是 1
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# str="/a.txt"
[root@localhost localhost]# test -e $str
[root@localhost localhost]# echo $?
0
​
语法参数 ------ 判断文件类型
-e 指定文件名是否存在
-f 指定文件名是否为文件
-d 指定文件名是否为目录
-b 指定的文件名是否为 block device装置
-c 指定的文件名是否为 character device装置
-S 指定的文件名是否为 Socket文件
-p 指定文件名是否为一个FIFO文件
-L 指定文件名是否为一个链接档
文件权限参数
-r 判断指定文件是都具备 读权限
-w 判断指定文件是否具备 写权限
-x 判断指定文件是否具备 执行权限
-u 判断指定文件是否具备 SUID的属性
-g 判断指定文件是否具备 SGID的属性
-k 判断指定文件是否具备 Sticky bit的属性
-s 判断指定文件是否为 非空白文件
    |- 真 是非空白文件 -----> 有内容
    |- 假 不是非空白文件 -----> 没有内容
[root@localhost localhost]# ll hello.sh
-rw-r--r--. 1 root root 18 11月 13 10:43 hello.sh
[root@localhost localhost]# test -r hello.sh
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test -w hello.sh
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test -x hello.sh
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# test -s a.txt
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# cat -E a.txt # 没有内容输出
[root@localhost localhost]#
​
文件比较参数
## 两个文件之间的比较
-nt (newer than) file1 -nt file2 判断 file1 是否比 file2 新
-ot (older than) file1 -ot file2 判断 file1 是否比 file2 旧
-ef file1 -ef file2 判断 file1 与 file2 是否为同一文件 可用于判断硬链接[判断这两个文件是否指向
同一个inode ]
### -nt 参数的演示
50674120 -rw-r--r--. 2 root root 11 11月 15 10:34 file1_hard.txt
50674120 -rw-r--r--. 2 root root 11 11月 15 10:34 file1.txt
50674122 -rw-r--r--. 1 root root 0 11月 15 10:35 file2.txt
[root@localhost localhost]# test file2.txt -nt file1.txt
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test file1.txt -nt file2.txt
[root@localhost localhost]# echo $?
1
## -ot 参数的演示
[root@localhost localhost]# test file1.txt -ot file2.txt
[root@localhost localhost]# echo $?
0
## -ef 参数的演示
[root@localhost localhost]# test file1.txt -ef file2.txt
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# test file1.txt -ef file1_hard.txt
[root@localhost localhost]# echo $?
0
整数之间的判定参数
## 关于两个整数之间的判定(针对变量数值大小的比较判断)
推荐是 [] 和 test使用比较的字符写法 因为使用 符号 > < != = >= <= 需要转义
-eq 两数值相等
-ne 两数值不等
-gt num1 -gt num2 num1是否大于num2
-lt num1 -lt num2 num1 是否小于 num2
-ge num1 -ge num2 num2 是否大于等于 num2
-le num1 -le num2 num1 是否小于等于 num2
[root@localhost localhost]# a=10
[root@localhost localhost]# b=20
[root@localhost localhost]# test $a -eq $b
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# test $a -ne $b
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test $a -gt $b
[root@localhost localhost]# echo $?
1
[root@localhost localhost]# test $a -lt $b
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test $a -le $b
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# test $a -ge $b
[root@localhost localhost]# echo $?
1
判定字符串的参数
-z
    test -z 字符串 判断字符串是否为空 "" 若为空 则为真
    若非空 则为假
-n
    test -n 字符串 判断字符串是否为 非空 ## -n 可以省略
        |- 若字符串是 非空 ------ 有内容 真
        |- 若字符串不是非空 ------ 没有内容 假
特例:
    test $str1 = $str2 判断 str1 是否 等于 str2 若相等 回传 true
    test $str1 != $str2 判断 str1 是否和 str2 不等 不等为 true 相等为假   
多重条件判断
-a (and)两种情况同时成立 例如 test -r file1 -a -x file1 判断 file1是否具备读写权限,都具备返回真,
否则返回假
-o (or)两种情况任何一个成立 例如 test -r file1 -o -w file1 判断 file1 是否具备读权限或者写权限
若具备读或者写权限,则返回真
! 取反 例如 test ! -r file1 若file1具备读权限,则为假 反之为真
[root@localhost localhost]# test -r file1.txt -a -w file1.txt
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# ll file1.txt
-rw-r--r--. 2 root root 11 11月 15 10:34 file1.txt
​
shell对于真假的判断逻辑。 提供了 && || !
A条件 && B条件
当A成立,才会执行B条件
A条件 || B条件
当A条件不成立时,才会执行B
​
## A条件 && B代码 A成立,才会执行B
[root@localhost localhost]# test -e heiheihei.txt && echo "这个嘿嘿嘿文件存在"
[root@localhost localhost]# touch heiheihei.txt
[root@localhost localhost]# test -e heiheihei.txt && echo "这个嘿嘿嘿文件存在"
这个嘿嘿嘿文件存在
## touch指令有两个作用: 1. 新建文件 2.修改文件的创建时间
[root@localhost localhost]# test -e heihei.txt && echo "这个嘿嘿嘿文件存在" || touch heihei.txt
[root@localhost localhost]# test -e heihei.txt && echo "这个嘿嘿嘿文件存在" || touch heihei.txt
这个嘿嘿嘿文件存在
[root@localhost localhost]# test -e hello && echo "hello文件夹已存在" || mkdir hello
[root@localhost localhost]# test -e hello && echo "hello文件夹已存在" || mkdir hello
hello文件夹已存在
### 判断 happy.txt 是否存在,若存在,判断是否为文件 思路[伪代码]
if( 文件存在 ){
    if (是文件){
        是文件
    }else{
        不是文件
    }
}else{
    不存在
}

中括号的条件测试

脚本中经常中括号进行条件测试

中括号[] test 和 [] 作用一样

### 注意事项
1. 在中括号中使用变量的值 "$变量名"
2. 中括号与测试表达式前后都要有空格
3. 若要进行比较,在中括号和 test 语句中使用 字符写法 ( -eq -ne -gt -lt -ge -le )
### test 的文件存在判定写法
[root@localhost localhost]# test -e test.txt && echo "文件存在" || echo "文件不存在"
文件不存在
[root@localhost localhost]# [ -e test.txt ]
[root@localhost localhost]# echo $?
1
##### [] 的文件判定存在写法 作用与 test 一致
[root@localhost localhost]# [ -e test.txt ] && echo "文件存在" || echo "文件不存在"
文件不存在
[root@localhost localhost]# filePath="/localhost/t1.sh"
### [] 判定是否为文件
[root@localhost localhost]# [ -f $filePath ] && echo " $filePath 是文件" || echo "不是文件"
/localhost/t1.sh 是文件
###[] 判定是否为文件夹
[root@localhost localhost]# [ -d "/localhost" ] && echo "是文件夹" || echo "不是文件夹"
是文件夹
###[] 判定文件是否有读权限,若有,则查看文件内容
[root@localhost localhost]# [ -r "$filePath" ] && cat $filePath
[root@localhost localhost]# [ -w "$filePath" ] && echo "HelloWorld" && cat $filePath
HelloWorld
#! /bin/bash
[ $# -ne 2 ] && {
echo "你必须传递两个参数"
exit 119 # 终止程序运行,且返回119状态码以后 提供给当前shell的 $?变量
}
echo "刚刚好传递了两个参数"
[root@localhost localhost]# [ -w "$filePath" ] && echo "HelloWorld" >> $filePath && cat $filePath
[root@localhost conf]# [ file1.txt -nt file2.txt ] && echo "file1.txt日期更新" || echo "file2.txt日期更新"
file2.txt日期更新
[root@localhost conf]# cd /localhost
[root@localhost localhost]# [ file1.txt -nt file2.txt ] && echo "file1.txt日期更新" || echo "file2.txt  日期更新"
file2.txt日期更新
[root@localhost localhost]# a=10
[root@localhost localhost]# b=20
[root@localhost localhost]# c=10
[root@localhost localhost]# d=5
[root@localhost localhost]# [ "$a" -eq "$b" ] && echo "两个数相等" || echo "两个数不相等"
两个数不相等
[root@localhost localhost]# [ 10 -eq 20 ] && echo "两个数相等" || echo "两个数不相等"
两个数不相等
[root@localhost localhost]# [ 10 -eq 20 ] && echo "两个数相等" || echo "两个数不相等"
两个数不相等
[root@localhost localhost]# ss=""
[root@localhost localhost]# [ -n "$ss" ] && echo $ss || echo "字符串为空"
字符串为空
[root@localhost localhost]# [ -n " " ] && echo $ss || echo "字符串为空"
[root@localhost localhost]# expr length "abc"
3
[root@localhost localhost]# expr length ""
0
[root@localhost localhost]# expr length " "
3
[root@localhost localhost]# [ 2 > 1 ] && echo "前者更大" || echo "后者更大"
前者更大
[root@localhost localhost]# [ 2 > 3 ] && echo "前者更大" || echo "后者更大"
前者更大
[root@localhost localhost]# [ 2 \> 3 ] && echo "前者更大" || echo "后者更大"
后者更大
​

 

双中括号

对单中括号的补充: 双中括号中 还支持 正则处理 在双中括号中 不需要转义字符可以识别特殊符号] 与 (()) 内部使用 比较字符 或者 比较符号 都可

### [[ 表达式 ]] 双中括号内部识别特殊字符
[root@localhost localhost]# [[ "$a" > "$b" ]] && echo "前者比后者大" || echo "后者比前者大"
后者比前者大
[root@localhost localhost]# [[ "$a" -gt "$b" ]] && echo "前者比后者大" || echo "后者比前者大"
后者比前者大

逻辑判断符号

&& -a
与运算 两边都为真 结果才为真
|| -o
或运算 两边有一个为真,结果就为真
[root@localhost localhost]# file1="/localhost/a.txt"
[root@localhost localhost]# file2="/localhost.txt"
[root@localhost localhost]#
[root@localhost localhost]#
[root@localhost localhost]# [ -e "$file1" -a -f "$file1" ] && echo "yes" || echo "no"
yes
[root@localhost localhost]# [ -e "$file2" -a -f "$file2" ] && echo "yes" || echo "no"
no
[root@localhost localhost]# [ -e "$file2" -o -f "$file2" ] && echo "yes" || echo "no"
no
[root@localhost localhost]# [ -e "$file2" -o -f "$file1" ] && echo "yes" || echo "no"
yes
## !表示对 -e "$file2" 结果取反 得到真 第二条件还是 假 真 -a 假 ----->假
[root@localhost localhost]# [ ! -e "$file2" -a -f "$file2" ] && echo "yes" || echo "no"
no
## 真 -a 假 --------> 假
[root@localhost localhost]# [ -e "$file1" -a -f "$file2" ] && echo "yes" || echo "no"
no
## 真 -a !(假)-------------真 -a 真 ------> yes
[root@localhost localhost]# [ -e "$file1" -a ! -f "$file2" ] && echo "yes" || echo "no"
yes
## 真 && 假 ------> no
[root@localhost localhost]# [[ -e "$file1" && -f "$file2" ]] && echo "yes" || echo "no"
no
## !(真) && 假 ------ 假 && 假 -----> no
[root@localhost localhost]# [[ ! -e "$file1" && -f "$file2" ]] && echo "yes" || echo "no"
no
## !(子shell执行返回假) -----> 真 yes
    [root@localhost localhost]# [[ ! (-e "$file1" && -f "$file2") ]] && echo "yes" || echo "no"
yes

if语句

单分支if

if 语句
单分支 if

if [ 条件表达式 ]
	then
		代码
fi
简化写法
if [ 条件表达式 ];then
	代码
fi
[root@localhost localhost]# cat if.sh
#! /bin/bash
echo "请输入(1-3)之间任意一个数字:"
read var1
if [ "$var1" -eq 1 ]
	then
		echo "黄焖鸡米饭出餐成功"
fi
if [ "$var1" -eq 2 ];then
	echo "麻辣香锅出餐成功"
fi
if [ "$var1" -eq 3 ]
	then
		echo "盖浇饭出餐成功"
fi

if语句的嵌套

if的嵌套 不要超过 三层
if [ 条件表达式 ]
	then
		代码
		if [ 条件表达式 ]
			then
				代码
		fi
fi
[root@localhost localhost]# cat if2.sh
#! /bin/bash
echo "请输入金额:"
read money
if [ "$money" -gt 1000000 ]
	then
		echo "先买辆车"
		money=$((money-300000))
		if [ "$money" -gt 1000000 ]
			then
				echo "再买个房"
		fi
fi

if-else结构

if [ 条件表达式 ]
	then
		代码1
else
	代码2
fi
### if-else 结构中可以继续嵌套
### 执行流程: 首先执行条件表达式的判断,若条件表达式成立,则执行代码1 若条件表达式不成立 则执行代码2
[root@localhost localhost]# cat happy.sh
#! /bin/bash
file1="/localhost/happy.txt"
if [ -e "$file1" ]
	then
		if [ -f "$file1" ]
			then
				echo "$file1 是文件"
		else
			echo "存在,但不是文件"
		fi
else
	echo "不存在,你可以新建"
fi
[root@localhost localhost]# cat happy.sh
#! /bin/bash
# file1="/localhost/happy.txt"
if [ -e "$1" ]
	then
		if [ -f "$1" ]
			then
				echo "$1 是文件"
		else
			echo "存在,但不是文件"
		fi
else
	echo "不存在,你可以新建"
fi

多分支

if [ 条件表达式1 ]
	then
		代码1
elif [条件表达式]
	then
		代码2
elif [条件表达式]
	then
		代码3
....
else
	代码
fi
#### 多分支 不要超过三层
### 买车
资金 10W 以内
买 秦
10W ~ 20W
买宋
20W ~ 30W
买su7
30W 以上
买房
[root@localhost localhost]# cat car.sh
#! /bin/bash
echo "请输入资金:"
read money
if [ "$money" -lt 100000 ]
	then
		echo "买帝豪"
elif [ "$money" -lt 200000 ]
	then
		echo "买比亚迪"
elif [ "$money" -lt 300000 ]
	then
		echo "买亚洲龙"
else
	echo "买房"
fi

函数

函数是一段功能代码,用来解决shell编程中冗余代码[重复且不连续出现的功能性代码]的问题

### 1. 先定义函数
函数名(函数的唯一标识) + 函数体(功能代码)
### 2. 调用函数
### 函数定义的语法
## 1. 标准shell的函数定义
function 函数名(){
	函数体
		linux命令
		if-else
		循环
		变量----(局部变量)
		return 返回值
}
## 2. 简化写法1
function 函数名{
	函数体
		linux指令
		if-else
		循环
		变量定义使用
		return 返回值
}
## 3. 简化写法2
函数名(){
	函数体
	return 返回值;
}
# 定义函数
function print(){
	echo "床前明月光"
	echo "疑是地上霜"
	echo "举头望明月"
	echo "低头思故乡"
	return 10
	
}
# 函数调用
print
print
  1. 执行函数时,直接写函数名即可 无需添加其他内容

  2. 函数必须先定义,再执行 ----- shell脚本是自上向下加载执行

  3. 想要在函数内部定义局部变量,使用 local 关键字

  4. 函数如果单独写入一个文件里,建议使用 source 去执行该文件

  5. 函数返回的结果,可以通过 $? 进行获取

return语句和exit语句
相同点:
	都可以让程序返回
不同点:
	1. return 只是代表当前函数执行结束,返回一个结果(返回值)
	2. exit 代表当前文件执行结束
	3. exit 结束当前shell环境,回到上一层 父shelll

函数实践

[root@localhost localhost]# cat fun3.sh
#! /bin/bash
#定义函数
function heihei(){
	cd ~
	echo "我准备创建一个文件,并追加写入信息"
	echo "小黑6666" >> ./demo.txt
	return 100
}
#调用函数(执行函数)
heihei
[root@localhost localhost]# ./fun3.sh ##### 开启子shell执行函数,变量和函数被加载到子shell环境中
我准备创建一个文件,并追加写入信息
[root@localhost localhost]# echo $?
100
[root@localhost localhost]# cat ~/demo.txt
小黑6666
小黑6666
小黑6666
小黑6666
小黑6666
[root@localhost localhost]# set | grep "heihei"
[root@localhost localhost]# ^C
[root@localhost localhost]# heihei ### 此时 函数和变量位于子shell环境 父shell 拿不到
-bash: heihei: 未找到命令
[root@localhost localhost]# source fun3.sh ### 将执行的变量和函数 引入当前的 shell环境[source其实是引用
当前的shel环境去执行文件 不开启子shell]
我准备创建一个文件,并追加写入信息
[root@localhost ~]# set | grep "heihei"
heihei ()
[root@localhost ~]# heihei
我准备创建一个文件,并追加写入信息
[root@localhost ~]# cat fun4.sh
#! /bin/bash
# 定义函数
ma(){
	echo "ma函数被调用执行---------"
	return 100
}
mb(){
	echo "mb函数被调用执行"
	return 110
}
#调用函数
ma
mb ### 后被调用 返回值 110 覆盖了 100
[root@localhost ~]# chmod +x fun4.sh
[root@localhost ~]# ./fun4.sh
ma函数被调用执行---------
mb函数被调用执行
[root@localhost ~]# echo $?
110
对于脚本的加载 在创建一个 fun5.sh 该脚本就是读取 ma 函数并调用
[root@localhost ~]# cat fun5.sh
#! /bin/bash
# 加载文件内的函数
[ -e ~/fun4.sh ] && . ~/fun4.sh || exit
#执行函数
ma
mb

函数脚本传入参数

分支结构--case

case 语句,主要是针对一个变量,进行多次 值比较 case语句相对 if来说 较为简便

语法:
case "变量" in
	值1)
		代码1
		;;
	值2)
		代码2
		;;
	值3)
		代码3
		;;
	*)
		代码4
esac
类似于
if---elif--elif----elif---else
[root@localhost localhost]# cat case1.sh
#! /bin/bash
echo "请输入点餐编号(1~3):"
read num
case "$num" in
	"1")
		echo "黄焖鸡米饭出餐"
		;;
	"2")
		echo "鸭腿饭出餐"
		;;
	"3")
		echo "麻辣香锅出餐"
		;;
	*)
		echo "您输入的数据不存在"
esac
[root@localhost localhost]# chmod +x case1.sh
[root@localhost localhost]# ./case1.sh
请输入点餐编号(1~3):
1
黄焖鸡米饭出餐
[root@localhost localhost]# ./case1.sh
请输入点餐编号(1~3):
2
鸭腿饭出餐
[root@localhost localhost]# ./case1.sh
请输入点餐编号(1~3):
3
麻辣香锅出餐
[root@localhost localhost]# ./case1.sh
请输入点餐编号(1~3):
4
您输入的数据不存在

循环结构

连续出现的功能性代码

shell循环有四种

while 设置条件,条件成立,循环就开始 之道循环条件不满足或者跳出结构位置

until 和whilc循环恰恰相反 条件不成立 循环开始 直到条件成立 循环结束

for

select

while 和 for 较为常用

while

主要用于程序的后台运行,需要持续运行的守护进程

while [ 条件表达式 ]
	do
		代码
done
### 无限次打印 HelloWorld
#! /bin/bash
num=1
while [ "$num" -lt 2 ]
	do
		echo "HelloWorld"
done
echo "while结构结束"
### 打印10次HelloWorld
1. 计数器
2. 打印一次 计数器++
3. 计数器的值 <= 10
[root@localhost localhost]# cat while1.sh
#! /bin/bash
num=1
while [ "$num" -lt 11 ]
	do
		echo "HelloWorld"
		((num+=1))
done
echo "while结构结束"
### 每3秒输出一次系统负载
#! /bin/bash
while [ 1 -lt 2 ]
	do
		uptime >> /localhost/uptime2.log # 打印系统的负载
		sleep 3 # 进程休眠3秒
done

###
指令 & ## 将进程放到后台运行
例如:
bash load1.sh &
jobs -l ## 查看后台正在运行的进程
[1]+ 2165 运行中 bash load1.sh &
## 计算 1+2+3+4+...+999+1000
#! /bin/bash
# 类和变量
sum=0
num=1
while [ $num -le 1000 ]
	do
		((sum=sum+num))
	((num++))
done
# echo 是打印技术内容以后自动换行
# echo "1~1000的和为: $sum"
printf "1~1000的和为:$sum \n"
printf "HelloWorld"
printf 在脚本中应用的比 echo 更广泛 ----- 可移植性强
语法:
printf 格式 展示的数据
printf使用文本或者空格分隔参数,也可以使用格式化字符串 还可以指定字符串的宽度,左右对其的方式
默认不换行 想换行 可以手动添加特殊字符 \n --- 换行符
[root@localhost localhost]# cat printf1.sh
#! /bin/bash
printf "%-10s %-8s %-4s %-8s %-4s \n" 姓名 性别 体重 年龄 成绩
printf "%-10s %-8s %-4s %-8s %-4.1f \n" 小黑 男 180 30 68.3214
printf "%-10s %-8s %-4s %-8s %-4.1f \n" 小白 女 100 25 85.6789
printf "%-10s %-8s %-4s %-8s %-4.1f \n" 小兰 女 80 30 85.6666
[root@localhost localhost]# bash printf1.sh
姓名 性别 体重 年龄 成绩
小黑 男 180 30 68.3
小白 女 100 25 85.7
小兰 女 80 30 85.7
%s 格式替换符 输出一个字符串
%c 格式替换符 输出一个字符
%d 格式替换符 整型输出
%f 格式替换符 输出小数
%-10s 指一个宽度为10的字符 (- 表示左对齐 没有则表示右对齐) 任何字符都会被显示在10个字符的宽度内 如
果内容不够10个字符,使用空格填充 若内容超过10个字符 超过也会将内容显示出来

until

不满足条件,才执行 满足则跳出结构

[root@localhost localhost]# cat until1.sh
#! /bin/bash
num=1
until [ $num -gt 10 ]
	do
		# 不满足条件才执行
		echo "HelloWorld"
		((num++))
done

for循环

写法 1:
	for 变量 in 变量取值的列表
		do
			代码
	done
执行流程:
	变量代表分别获取每个值 值取完了 结构退出
写法2:
	for ((expr1;expr2;expr3))
	for ((变量初始化定义;设置变量的取值范围;变量递增递减))
	C语言
		for(int i=0;i<=10;i++)
[root@localhost localhost]# cat for1.sh
#! /bin/bash
for var in 1 2 3 4 5 6 7 8 9 10
	do
		echo $var
done
echo "------------------------------------"
for var in {1..10}
	do
		echo $var
done
echo "-------------------------------------"
for var in `seq 10`
	do
		echo $var
done	
##打印10次helloWorld
[root@localhost localhost]# cat for2.sh
#! /bin/bash
for var in {1..10}
	do
		echo "HelloWorld"
done
## 计算 1+2+3+4+...+999+1000
[root@localhost localhost]# cat for3.sh
#! /bin/bash
sum=0
for var in {1..1000}
	do
		((sum=var+sum))
done
echo "1~1000的和为 $sum"
## 打印 1 ~ 10 第二种写法
[root@localhost localhost]# cat for4.sh
#! /bin/bash
for ((num=1;num<=10;num++))
	do
		echo $num
done
## 列出某个目录下的文件
[root@localhost localhost]# ls /localhost
1 b.txt demo.sh for1.sh fun1.sh happy.txt hello.sh printf1.sh t1.sh
while1.sh
3 car.sh file1_hard.txt for2.sh fun2.sh heiheihei.txt if2.sh read.sh
test_and_or.sh while2.sh
abc.sh case1.sh file1.txt for3.sh fun3.sh heihei.txt if.sh special2.sh
until1.sh world.sh
a.txt c.txt file2.txt for4.sh happy.sh hello load1.sh special.sh
uptime2.log
[root@localhost localhost]# vim for5.sh
[root@localhost localhost]# cat for5.sh
#! /bin/bash
for file in `ls /localhost`
	do
		echo $file
done
## 列出某个文件夹下所有的文件(包含子文件夹内部的文件)
思路:
for var in 目录
do
1.var 可能是文件
echo $var
2. var 是个文件夹
列出该文件夹下的所有文件
----- 开发函数(列出指定文件夹下所有的文件)
[root@localhost localhost]# cat fun8.sh
#! /bin/bash
# 函数的能:列出指定文件夹下所有的文件
function list_files(){
    for var in `ls $1` # $1是目录
    	do
    		dir_file="$1/$var" # 例如 $var hello文件夹 /localhost/hello
            # 进行目录的递归搜索
            # 搜索获取的 var 可能是文件 也可能是目录
            # -f判断是否为文件 -d 判断是否为目录
            # 若 var 是文件 打印
            # 若 var 是目录 再次调用该函数
            if [ -f "$var" ]
            	then
            		echo "$dir_file"
            else
            	list_files "$dir_file"
            fi
    done
}
list_files $1

循环控制

中断循环

办法1:
循环条件不满足
办法2:
break 中断循环
continue 直接中断本次循环,进入下一次
exit 退出脚本,退出当前shell
return 用在函数中 结束函数的作用

break 关键字 break n [n代表跳出的循环层数]

##打印6次HelloWorld
[root@localhost localhost]# cat break1.sh
#! /bin/bash
for var in {1..10}
    do
        if [ $var -le 6 ]
            then
            	echo "HelloWorld"
        else
       		break
        fi
done
## break n 的特点
[root@localhost localhost]# cat break2.sh
#! /bin/bash
for var in {1..10} # 外层循环
    do
        echo "外层循环的执行"
        for tmp in {1..10}
            do
                if [ $tmp -le 6 ]
                	then
                		printf "$tmp "
                else
                	break
                fi
        done
        printf "\n"
done
[root@localhost localhost]# bash break2.sh
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
外层循环的执行
1 2 3 4 5 6
[root@localhost localhost]# bash break2.sh
外层循环的执行
1 2 3 4 5 6 [root@localhost localhost]# cat break2.sh
#! /bin/bash
for var in {1..10} # 外层循环
    do
        echo "外层循环的执行"
        for tmp in {1..10}
            do
                if [ $tmp -le 6 ]
                	then
                		printf "$tmp "
                else
                	break 2 ## 跳出第二层循环
                fi
        done
        printf "\n"
done

contine 跳过本次循环,直接进入下一次循环

[root@localhost localhost]# bash break1.sh
HelloWorld 1
HelloWorld 2
HelloWorld 3
HelloWorld 4
HelloWorld 5
HelloWorld 6
HelloWorld 8
HelloWorld 9
HelloWorld 10
[root@localhost localhost]# cat break1.sh
#! /bin/bash
for var in {1..10}
    do
        if [ $var -eq 7 ]
        	then
        	continue
        fi
        	echo "HelloWorld $var"
done

数组

数组变量中,可以存储多个值。
数组,就是多个元素的集合,能够把多个元素,通过一个变量名进行存储 然后再给元素挨个打标记[下标]
特征:
1. 数组内的值相互独立
2. 数组内每个值的标识-----下标{可以连续 可以不连续}

数组定义的语法

数组名=(值1 值2 值3 值4...)
[root@localhost localhost]# name="小黑 小白 小兰 小红"
[root@localhost localhost]# echo $name
小黑 小白 小兰 小红
[root@localhost localhost]# set | grep "name"
name='小黑 小白 小兰 小红'
[root@localhost localhost]# array1=(小黑 小白 小兰 小红)
[root@localhost localhost]# set | grep "array1"
array1=([0]="小黑" [1]="小白" [2]="小兰" [3]="小红")

基础操作

## 1. 声明并赋值
array=("小黑" "小白" "小兰")
## 2. 键值对的赋值方式来创建数组
heros=([0]="程咬金" [1]="花木兰" [2]="芈月" [3]="伽罗")
heros2=([3]="小乔" [1]="大乔" [5]="安其拉" [2]="典韦")
## 3.动态定义数组
myArray=(`ls /localhost`) ## 反引号的特点是先执行指令,再将指令输出
myArray1=($(ls /localhost)) ## 作用同上
## 4. 采用命令创建数组
declare -a 数组名 ## 不推荐

获取元素

## 1. 获取指定数组元素
${数组名[下标]}
[root@localhost localhost]# echo ${heros[0]}
程咬金
[root@localhost localhost]# echo ${heros[1]}
花木兰
## 2.获取所有数组元素
[root@localhost localhost]# echo ${heros[*]}
程咬金 花木兰 芈月 伽罗
[root@localhost localhost]# echo ${heros[@]}
程咬金 花木兰 芈月 伽罗
## 3.获取数组长度
[root@localhost ~]# echo ${#heros[@]}
4
[root@localhost ~]# echo ${#heros[*]}
4

修改元素

[root@localhost localhost]# heros=([0]="程咬金" [1]="花木兰" [2]="芈月" [3]="伽罗")
[root@localhost localhost]# set | grep "heros"
heros=([0]="程咬金" [1]="花木兰" [2]="芈月" [3]="伽罗")
[root@localhost localhost]# heros2=([3]="小乔" [1]="大乔" [5]="安其拉" [2]="典韦")
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# set | grep "^sero"
[root@localhost localhost]# set | grep "^hero"
heros=([0]="程咬金" [1]="花木兰" [2]="芈月" [3]="伽罗")
heros2=([1]="大乔" [2]="典韦" [3]="小乔" [5]="安其拉")
[root@localhost localhost]# heros2=([3]="小乔" [1]="大乔" [5]="安其拉" [2]="典韦" [1]="妲己")
[root@localhost localhost]# echo $?
0
[root@localhost localhost]# set | grep "^hero"
heros=([0]="程咬金" [1]="花木兰" [2]="芈月" [3]="伽罗")
heros2=([1]="妲己" [2]="典韦" [3]="小乔" [5]="安其拉")
注意:
1. 下标可以不连续,可以指定下标,存储时,会按照下标进行排序存储
2. 若下标冲突,元素之间会出现覆盖

删除数组元素

## 1. 删除所有数组元素
unset 数组名
## 2.单独删除某个数组元素
unset 数组名[下标]

标签:shell,##,echo,sh,linux,root,localhost
From: https://blog.csdn.net/buzhi______/article/details/141988063

相关文章

  • Linux 性能优化(网络、磁盘、内存、日志监控)
    1、CPU性能监控1.2、平均负载基础平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和CPU使用率并没有直接关系。平均负载其实就是平均活跃进程数。平均活跃进程数,直观上的理解就是单位时间内的活跃进程数。查看cpu个数:grep'modelnam......
  • mysql在linux安装
    在Linux上安装MySQL5.7版本的步骤可以分为多个部分,包括下载、安装、配置以及启动MySQL服务。以下是一个详细的步骤指南:一、下载MySQL5.7安装包访问MySQL官方网站:前往MySQL官方网站下载适用于Linux的MySQL5.7安装包。通常,你会找到如mysql-5.7.xx-linux-glibc2.xx-x86_64.tar.......
  • 反弹shell
    反弹shellLinux系统环境什么是反弹shell反弹Shell是一种网络攻击技术,用于通过远程主机上的Shell(命令行终端)与攻击者建立连接,从而控制受攻击主机。攻击者通常在受攻击主机上以各种方式植入恶意代码(如后门程序),然后通过网络与该主机上运行的Shell建立反向连接,从而获得对该主机的完......
  • 如何在Java中获取Windows和Linux/Mac系统上的桌面路径
    在Java中,你可以使用System.getenv()方法来获取环境变量。对于获取桌面路径,你可以根据操作系统的不同来获取相应的环境变量。对于Windows系统,你可以尝试获取USERPROFILE环境变量,它通常指向当前用户的主目录,而Windows的桌面通常位于此目录下的Desktop文件夹内。对于Linux和Mac系统......
  • Linux中的Vim文本编辑器
    Linux中的Vim是一个非常强大的文本编辑器,它提供了丰富的命令来支持各种文本编辑操作。以下是一个Vim常用命令的详细总结,涵盖了基本操作、编辑命令、移动光标、查找替换、保存退出等多个方面。一、基本操作启动Vimvim:直接启动Vim编辑器。vimfilename:打开或创建文件并启......
  • Linux查询端口是否被占用的四种方法
    一个面试题,使用三种不同的方法查看8080被哪个进程占用了。通常比较熟悉的方法是netstat和lsof两种,但还有什么方法呢。1.netstat或ss命令netstat-anlp|grep802.lsof命令这个命令是查看进程占用哪些文件的lsof-i:803.fuser命令fuser命令和lsof正好相反,是查看某个文......
  • Linux日志-sar日志
    作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。Linux系统中的日志是记录系统活动和事件的重要工具,它们可以帮助管理员监视系统状态、调查问题以及了解系统运行状况。主要涉及到系统日志,登录日志,......
  • Linux中的进程优先级与设置方法
    在Linux系统中,进程优先级是影响进程调度的重要因素。进程优先级决定了操作系统在多任务环境中分配CPU时间的方式。以下是关于Linux中进程优先级的详细介绍及其设置方法。1.进程优先级概述优先级范围:Linux中的优先级通常使用一个值来表示,范围从0到139:实时优先级:范......
  • Linux内核模块的加载与卸载过程
    在Linux中,内核模块是一种可加载的代码,允许动态扩展内核的功能,而无需重启系统。以下是内核模块的加载与卸载过程的详细说明。1.内核模块的概述内核模块:是一个包含可以被Linux内核动态加载和卸载的代码的文件。通常以.ko(KernelObject)为后缀。用途:可以用于添加驱动程序、......
  • [Linux][Mysql]Linux使用MySQL Yum存储库上安装MySQL 5.6
    Linux使用MySQLYum存储库上安装MySQL5.6,适用于OracleLinux,RedHatEnterpriseLinux和CentOS系统。一、全新安装MySQL1、添加MySQLYum存储库将MySQLYum存储库添加到系统的存储库列表中。这是一次性操作,可以通过安装MySQL提供的RPM来执行。跟着这些步骤:1.1、到MySQL官......