转一下 发表于 2023-7-7 05:03:20

Shell

Shell

Shell概述

1.什么是Shell
Shell是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户每输入一条命令,Shell就解释执行一条。这种从键盘一输入命令,就可以立即得到回应的对话方式,称为交互的方式。
2.Shell脚本
当命令或程序语句不在命令行下执行,而是通过一个程序文件来执行时,该程序就被称为Shell脚本。如果在Shell脚本里内置了很多条命令、语句及循环控制,然后将这些命令一次性执行完毕,这种通过文
件执行脚本的方式称为非交互的方式。
3.Shell的分类
Shell脚本语言是弱类型语言(无须定义变量的类型即可使用),在Unix/Linux中主要有两大类Shell:一
类是Bourne shell,另一类是C shell。
4.Shell脚本语言的优势
Shell脚本语言的优势在于处理偏操作系统底层的业务,例如:Linux系统内部的很多应用(有的是应用的一部分)都是使用Shell脚本语言开发的。
对于一些常见的系统脚本,使用Shell开发会更简单、更快速,例如:让软件一键自动化安装、优化,监控报警脚本,软件启动脚本,日志分析脚本等。
5.脚本开头
在执行bash脚本的时候,内核会根据“#! ”后的解释器来确定该用哪个程序解释这个脚本中的内容。
#!/bin/bash6.Shell脚本的执行
Shell脚本是从上至下依次执行每一行的命令及语句的,即执行完了一个命令后再执行下一个,如果在Shell脚本中遇到子脚本(即脚本嵌套)时,就会先执行子脚本的内容,完成后再返回父脚本继续执行父脚本内后续的命令及语句。
通常情况下,在执行Shell脚本时,会向系统内核请求启动一个新的进程,以便在该进程中执行脚本的命令及子Shell脚本。
Shell脚本的执行通常可以采用以下几种方式。
bash script-name
`bash script-name或sh script-name:这是当脚本文件本身没有可执行权限(即文件权限属性x位
为-号)时常使用的方法,或者脚本文件开头没有指定解释器时需要使用的方法。`


./script-name
`path/script-name或 ./script-name:指在当前路径下执行脚本(脚本需要有执行权限),需要将
脚本文件的权限先改为可执行(即文件权限属性加x位),具体方法为chmod +x script-name。然
后通过脚本绝对路径或相对路径就可以直接执行脚本了。`

source script-name
source script-name或.script-name:这种方法通常是使用source或“.”(点号)读入或加载指定
的Shell脚本文件,然后,依次执行指定的Shell脚本文件san.sh中的所有语句。这些语句将在当前
父Shell脚本father.sh进程中运行(其他几种模式都会启动新的进程执行子脚本)source或“.”命令的功能是:在当前Shell中执行source或“.”加载并执行的相关脚本文件中的命令及语句,而不是产生一个子Shell来执行文件中的命令。注意“.”和后面的脚本名之间要有空格。因此,使用source或“.”可以将自身脚本中的变量值或函数等的返回值传递到当前父Shell脚本father.sh中使用。这是它和其他几种方法最大的区别
`创建sh文件 `
# cd /opt
# mkdir scripts
# cd scripts/
# vim hello.sh
#! /bin/bash
echo "hello world!"

`bash hello.sh`
# bash hello.sh
hello world!

`./hello.sh`
# ./hello.sh
-bash: ./hello.sh: 权限不够
# ls -l
总用量 4
-rw-r--r--. 1 root root 33 7月   5 22:45 hello.sh

`添加执行权限`
# chmod +x hello.sh
# ./hello.sh
hello world!

`直接输入 会被当作命令 命令没有写进文件`
# hello.sh
-bash: hello.sh: 未找到命令

`source.执行脚本`
# source hello.sh
hello world!
# . hello.sh
hello world!

`source.执行脚本会在当前shell进程执行 而上面两种会开辟一个子shell进程去执行脚本`Shell变量

1.变量的基本概念
变量用于存储程序中使用的数据,所存储的数据存在于内存空间中,通过变量的名字就可以取出与变量
对应的数据,变量定义的语法:
变量名称=值注意”=“的两侧无空格,否则变量名称会被识别为命令,变量的内容一般要加双引号,以防止出错,特别
是当值里的内容之间有空格时。默认情况下,在bash Shell中是不会区分变量类型的,例如:常见的变量类型为整数、字符串、小数等。这和其他强类型语言(例如:Java/C语言)是有区别的。
定义变量,并输入变量的值
a=5
echo $a #通过echo命令加上$即可输出变量的值2. 子进程Shell与变量的可见性
`查看当前和终端相关的进程信息,可以看到只有一个“-bash”进程,此进程也是目前正在使用的bash
shell进程。通过执行 bash命令可以基于当前的shell进程再开启一个新的bash shell进程,既子shell进程`
# ps -f
UID         PID   PPIDC STIME TTY          TIME CMD
root       1375   13710 7月05 pts/0   00:00:00 -bash
root       1598   13750 00:07 pts/0    00:00:00 ps -f

# bash

# ps -f
UID         PID   PPIDC STIME TTY          TIME CMD
root       1375   13710 7月05 pts/0   00:00:00 -bash
root       1600   13750 00:09 pts/0    00:00:00 bash
root       1612   16000 00:09 pts/0    00:00:00 ps -f
`可以看到bash进程的父进程(PPID)是 -bash 1375`

# exit
exit
# ps -f
UID         PID   PPIDC STIME TTY          TIME CMD
root       1375   13710 7月05 pts/0   00:00:00 -bash
root       1614   13750 00:14 pts/0    00:00:00 ps -f

`在子Shell中创建的变量上一级Shell是看不到的(显示空的),反之也一样`
# a=1
# echo $a
1
# bash
# echo $a

# b=2
# echo $b
2
# exit
exit
# echo $b

#

`上节所述:`
`source.执行脚本会在当前shell进程执行 而上面两种会开辟一个子shell进程去执行脚本`

`继续测试`
`默认环境我们定义了变量a,我们再写一个.sh文件 让它直接echo $a 在不同shell环境下执行试试`
# vim a.sh
#! /bin/bash
echo $a
# ps -f
UID         PID   PPIDC STIME TTY          TIME CMD
root       1375   13710 7月05 pts/0   00:00:00 -bash
root       1654   13750 00:26 pts/0    00:00:00 ps -f
# echo $a
1
# bash a.sh

# chmod +x a.sh
# ./a.sh

# source a.sh
1
# . a.sh
1
# 3.变量的类型
变量可分为两类:环境变量(全局变量)和普通变量(局部变量)。
环境变量也可称为全局变量,可以在创建它们的Shell及其派生出来的任意子进程Shell中使用,环境变量又可分为自定义环境变量和bash内置的环境变量。
普通变量也可称为局部变量,只能在创建它们的Shell函数或Shell脚本中使用。普通变量一般由开发者在开发脚本程序时创建。
4.环境变量
如何让局部变量(普通变量)变为环境变量呢?
在前面加export
环境变量一般是指用export内置命令导出的变量,用于定义Shell的运行环境,保证Shell命令的正确执行。
Shell通过环境变量来确定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、Shell脚本和各类应用。
5.系统环境变量
环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在以下位置配置:

[*]用户家目录下的.bash_profile或.bashrc(非用户登录模式特有,例如远程SSH)文件中
[*]全局配置/etc/bashrc(非用户登录模式特有,例如远程SSH)或/etc/profile文件中定义
在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用export命令导出定义,例如:正确的环境变量定义方法为
export FLAG=1测试:
# ps -f
UID         PID   PPIDC STIME TTY          TIME CMD
root       1375   13710 7月05 pts/0   00:00:00 -bash
root       1776   13750 01:17 pts/0    00:00:00 ps -f
# export A=300
# echo $A
300
# bash
# echo $A
300

`查看环境变量`
# env
XDG_SESSION_ID=2
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.70.1 60151 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root

`显示当前Shell中所有变量`
# set

`如果想要设置环境变量,就要在给变量赋值之后或在设置变量时使用export命令,此处不要在变量名前面加$`
export A=100

A=100
export A

对于用户的环境变量设置,比较常见的是用户家目录下的.bashrc和.bash_profile。
全局环境变量的配置文件,一般放在/etc/bashrc,/etc/profile中6.显示与取消环境变量
`通过echo打印环境变量,常见系统环境变量:`
        $HOME:用户登录时进入的目录。
        $UID:当前用户的UID(用户标识)
        $PWD:当前工作目录的绝对路径名
        $SHELL:当前SHELL。
        USER:当前用户
       
# echo $HOME
/root

`用unset消除本地变量和环境变量`
echo $USER
unset USER #可以看到变量的内容显示为空。7.普通变量
为普通变量的定义赋值,一般有以下3种写法:
变量=value
变量='value
变量="value"

变量的内容可以用单引号或双引号引起来,也可不加引号,但是这三者的含义是不同的,运行如下脚本
#! /bin/bash
a=192.168.1.10-$a
b='192.168.1.10-$a'
c="192.168.1.10-$a"
echo "a=$a"
echo "b=$b"
echo "c=${c}"

# vim test.sh
`复制上面脚本内容`
# source test.sh
a=192.168.1.10-
b=192.168.1.10-$a
c=192.168.1.10-192.168.1.10-

`我们可以发现`
不加引号时,值里有变量的会被解析后再输出
单引号,单引号里是什么就输出什么
双引号,输出变量内容时引号里的变量及命令会经过解析后再输出内容
==通常,数字内容的变量定义可以不加引号,其他没有特别要求的字符串等定义最好都加上双引号==Shell变量进阶

1.将命令结果赋值给变量
变量=`ls`
变量=$(ls)

# a=`hostname`
# echo $a
localhost.localdomain

# a=$(pwd)
# echo $a
/opt/scripts

`在变量名前加$可以取得该变量的值,使用echo命令可以显示变量的值,$A和${A}的写法不同,但效果是一样的`
==当变量后面连接有其他字符的时候,必须给变量加上大括号{}==

# a='zhangsan'
# echo $a_xiaozhang

# echo ${a}_xiaozhang
zhangsan_xiaozhang2.特殊变量
在Shell中存在一些特殊且重要的变量,例如:$0、$1、$#,我们称之为特殊位置参数变量。
https://www.cnblogs.com/img/image-20230706095133384.png
$n
`要从命令行、函数或脚本执行等处传递参数时,就需要在Shell脚本中使用位置参数变量。`
# vim p.sh
# cat p.sh
#! /bin/bash
echo $1
# bash p.sh

# bash p.sh xuxu
xuxu

# vim p.sh
# cat p.sh
#! /bin/bash
echo $1 $2
# bash p.sh xuxu xuxuxu
xuxu xuxuxu

`在脚本中快速生成多个变量`
echo \${1..15} #相当于 echo $1 ... $15
       
# echo \${1..15}
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
# echo \${1..15} > x.sh
# vim x.sh
# cat x.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
# bash x.sh zhangsan lisi wangwu
zhangsan lisi wangwu zhangsan0 zhangsan1 zhangsan2 zhangsan3 zhangsan4 zhangsan5
`当位置参数数字大于9时,需要用大括号将数字括起来,如:${10},否则会出现异常`$0
$0的作用为取出执行脚本的名称(包括路径)
root@localhost scripts]# vim n.sh
# cat /opt/scripts/n.sh
echo $0
# bash n.sh
n.sh
# cd /
# bash /opt/scripts/n.sh
/opt/scripts/n.sh时如果希望单独获取名称或路径,则可用dirname及basename命令
dirname /opt/server/a.txt
basename /opt/server/a.txt利用$0和上述命令(dirname、basename)分别取出脚本名称和脚本路径。
# vim n.sh
# cat /opt/scripts/n.sh
dirname $0
basename $0
# cd /
# bash /opt/scripts/n.sh
/opt/scripts
n.sh$#
通过$#获取脚本传参的个数
# vim q.sh
# cat q.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9
echo $#
# bash q.sh {a..z}
a b c d e f g h i
26
`可以看到$#输出的26 因为传递的是a-z 26字母 打印的是前9个`$*$@
利用set设置位置参数
表示清除所有的参数变量,重新设置后面的参数变量
# set -- zhangsan lisi wangwu
# echo $1
zhangsan
# echo $3
wangwu

# echo $*
zhangsan lisi wangwu
# echo $@
zhangsan lisi wangwu测试\(*和\)@,注意,此时不带双引号:
# echo $*
zhangsan lisi wangwu
# echo $@
zhangsan lisi wangwu

# for i in $*;do echo $i;done
zhangsan
lisi
wangwu
# for i in $@;do echo $i;done
zhangsan
lisi
wangwu测试"\(*"和"\)@",注意,此时带有双引号:
# echo "$*"
zhangsan lisi wangwu
# echo "$@"
zhangsan lisi wangwu

`主要区别 $*会把所有参数当作一个整体`
# for i in "$*";do echo $i;done
zhangsan lisi wangwu
# for i in "$@";do echo $i;done
zhangsan
lisi
wangwu$?
$?用于获取执行上一个指令的执行状态返回值,0表示成功,非0表示失败
#
# pwd
/opt/scripts
# echo $?
03.内置变量命令
bash Shell包含一些内置命令。这些内置命令在目录列表里是看不见的,它们由Shell本身提供。常用的内部命令有:echo、eval、exec、export、read、shift。下面简单介绍几个最常用的内置命令的格式和功能。
eval
eval,当Shell程序执行到eval语句时,Shell读入参数args,并将它们组合成一个新的命令,然后执行
# vim noeval.sh
# cat noeval.sh
echo \$$#
# bash noeval.sh a1 a2
$2
# vim noeval.sh
# cat noeval.sh
eval echo \$$#
# bash noeval.sh a1 a2
a2
`相当于echo $2`Shell运算符与条件测试

1.算术运算符
https://www.cnblogs.com/img/image-20230706111321856.png
算术运算符号均适用于常见的运算命令,常见算术运算命令如下
https://www.cnblogs.com/img/image-20230706111425678.png
”(())”****数值运算
双小括号“(())”的作用是进行数值运算与数值比较
https://www.cnblogs.com/img/image-20230706111509590.png
利用“(())”进行简单的数值计算
# a=1+1
# echo $a
1+1
# echo $((a))
2
# echo $((1+1))
2利用“(())”双括号进行比较及判断
# echo $((1>2))
0
# echo $((1<2))
1在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符
# echo $((1+1))
2
# echo $
2文件测试表达式
这些操作符号对于[[]]、[]、test的测试表达式是通用的
https://www.cnblogs.com/img/image-20230706160254996.png
字符串测试操作符
字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为NULL等
https://www.cnblogs.com/img/image-20230706160356825.png
对于字符串的测试,一定要将字符串加双引号之后再进行比较
比较符号(例如=和!=)的两端一定要有空格
# i=2
# i=i+8
# echo $i
i+8
# i=2
# let i=i+8
# echo $i
10整数二元比较操作符
在书写测试表达式时,可以使用表中的整数二元比较操作符。
https://www.cnblogs.com/img/image-20230706161030944.png
=”和“! =”也可在[]中做比较使用,但在[]中使用包含“>”和“<”的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能会不对。
也可以在[[]]中使用包含“-gt”和“-lt”的符号,但是不建议这样使用。
# expr 2 + 2
4
# expr 2+2
2+2
# name=zhangsan
# expr length $name
8二元数字在(())中的比较
# echo "7.5 2.5" | awk '{print ($1-$2)}'
5逻辑操作符
https://www.cnblogs.com/img/image-20230706162821533.png
测试表达式test、[]、[[]]、(())的区别总结
https://www.cnblogs.com/img/image-20230706162834187.png
选择语句

1.if语句基本用法
单分支结构
test <测试表达式>

# test -f /tmp/xx.txt && echo 1 || echo 0
0
#[ -f /tmp/xx.txt ] && echo 1 || echo 0
0双分支结构
# [[ 2 > 1 && 3 > 2 ]] && echo 1 || echo 0
1多分支结构
# [ 2 > 1 -a 3 > 2 ] && echo 1 || echo 0
1
# [ 2 > 1 && 3 > 2 ] && echo 1 || echo 0
-bash: [: 缺少 `]'
0
# [ 2 -gt 1 && 3 -lt^C ] && echo 1 || echo 22.read命令
Shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入中获得
-p prompt:设置提示信息。
-t timeout:设置输入等待的时间,单位默认为秒。
# name=zhangsan
# [ -n "$name" ] && echo 1 || echo 0
1
# [ "abc" = "ab" ] && echo 1 || echo 0
0
# [ "abc" == "ab" ] && echo 1 || echo 0
0# [ 2 < 1 ] && echo 1 || echo 2
1
# [ 2 -lt 1 ] && echo 1 || echo 2
23.case语句
支持正则
# ((2>1)) && echo 1 || echo 0
1
# ((2==1)) && echo 1 || echo 0
0循环语句

<blockquote>1.while循环语句
# vim if-test.sh
#! /bin/bash
if [ "$1" -gt 10 ];then
      echo 1
else
      echo 0
fi
# bash if-test.sh 20
12.until循环语句
# vim if-test2.sh
if [ "$1" -gt 60 ];then
      echo 1
else
      echo 2
fi
# bash if-test2.sh 10
2
# bash if-test2.sh 100
13.脚本后台运行
通过在脚本的结尾使用&符号来在后台运行脚本:
# vim if-test3.sh
#! /bin/bash
if [ "$1" -gt 60 ];then
      echo 1
elif [ $1 -gt 35 ];then
      echo 2
elif [ $1 -gt 18 ];then
      echo 3
else
      echo 4
fi
# bash if-test3.sh 80
1
# bash if-test3.sh 40
2
# bash if-test3.sh 20
3
# bash if-test3.sh 10
44.for循环
第一种方式:# vim for-test.sh#! /bin/bashfor i in 1 2 3do      echo $idone# bash for-test.sh123第二种方式(C语言型for循环):# vim for-test2.sh#! /bin/bashfor (( i=1;i
页: [1]
查看完整版本: Shell