Linux入门三-shell编程

Linux入门三-shell编程一、什么是shellshell一般代表两个层面的意思,一个是命令解释器,比如BASH,另外一个就是shell脚本。现在我们站在命令解释器的角度来阐述shell注意,shell里面没有缩进子代码的概念,全靠语法关键字来辨别,导致我们的代码看起来很吃力,所以需要我们人为手动去给它书写格式。==一般会

大家好,欢迎来到IT知识分享网。Linux入门三-shell编程"

一、什么是shell

  • shell一般代表两个层面的意思,一个是命令解释器,比如BASH,另外一个就是shell脚本。现在我们站在命令解释器的角度来阐述shell
  • 注意,shell里面没有缩进子代码的概念,全靠语法关键字来辨别,导致我们的代码看起来很吃力,所以需要我们人为手动去给它书写格式。一般会 空格4次 再书写子代码,尽量不要用Tab去缩进
  • #!/bin/bash的作用:
    • 一般出现在script文件(.sh文件)的首行,作用是先启用新的sub-shell(新的子进程),然后在其下使用/bin/bash解释器去执行命令
    • 默认的解释器是/bin/bash,此外,Linux中的shell还有/bin/sh ; /sbin/nologin ; /bin/dash ; /bin/tcsh ; /bin/csh

二、命令优先级

命令分为:
执行一个命令之后,shell解释器的查找该命令的路径的优先级

==> alias  # 先找别名
  ==> Compound Commands  # 再找流程控制  if  for  while
    ==> function  # 再找函数名
      ==> build_in  # 再找shell内置的命令
        ==> hash  # 再找缓存
          ==> $PATH  # 最后去PATH里找
            ==> error: command not found  # 上面都找不到,就报错

$PATH是一个环境变量,它包含了一系列用冒号分隔的目录路径,用来指示 shell 在哪些目录中查找可执行文件。Linux系统中,当我们在终端输入一个命令时,系统会在$PATH中指定的目录中查找该命令对应的可执行文件,如果找到了就执行该文件,否则就会提示“command not found”。

默认情况下,$PATH包含了一些常用的目录路径,如/bin、/usr/bin、/usr/local/bin等。我们可以通过修改$PATH变量来添加或删除目录路径,以便让系统能够在更多的目录中查找可执行文件。例如,可以在.bashrc文件中添加一行类似于export PATH=$PATH:/home/user/mybin的语句,将/home/user/mybin目录添加到$PATH中。

注意,$PATH变量的顺序很重要,系统会按照$PATH中目录路径的顺序依次查找可执行文件,如果在前面的目录中找到了对应的文件,就不会再去后面的目录中查找了。因此,如果我们想要覆盖系统自带的命令,可以将自己的目录路径添加到$PATH的最前面                

1. 别名

linux设置、添加别名(centos):   

1. 查看别名
alias  # 显示当前系统上所有的别名及其相应的命令

2. 添加临时别名(当前bash有效,关闭bash后失效)
alias 别名=[指令名称]  # 如:alias ll='ls -alF'

3. 删除别名
unalias 别名

4. 为指定用户添加永久的别名
在用户根目录下,修改.bashrc文件,在文件最后添加别名。例如在文件最后添加:alias mv='mv -i',这样就添加mv为一个当前用户的永久的别名了。修改文件后,要重新打开终端才生效

5. 为系统所有用户添加永久的别名
进入目录/etc/profile.d/,添加一个自定义的后缀为.sh的文件,例如myshell.sh,如果之前添加过自定义的.sh文件就不用新创建文件了。类似地,修改文件myshell.sh,在文件最后添加别名就行,例如在文件最后添加:alias mv='mv -i',这样就为系统添加了一个所有用户都适用的永久的别名了。修改文件后,要重新打开终端才生效

2. linux的环境变量

(1)登录bash时加载的环境变量文件

  • 共5种环境变量文件
    • /etc/profile
    • /etc/bashrc
    • /用户目录/.bashrc
    • /用户目录/.bash_profile
    • /etc/profile.d/*.sh (profile.d下的全部sh文件)
  • 加载顺序:/etc/profile——》/etc/profile.d/*.sh——》/用户目录/.bash_profile——》/用户目录/.bashrc——》/etc/bashrc
  • 不推荐修改/etc/profile文件

(2)非登录bash时加载的环境变量文件

  • 共3种环境变量文件
    • /用户目录/.bashrc
    • /etc/bashrc
    • /etc/profile.d/*.sh
  • 加载顺序:/用户目录/.bashrc——》/etc/bashrc——》/etc/profile.d/*.sh
  • 所有想要永久固化命令且为所有用户可用,可以修改/etc/bashrc或者/etc/profile.d/*.sh

(3)手动加载环境变量文件

使用 source 命令

source 环境变量文件路径

如:
source ~/.bashrc
source /etc/bashrc

(4)linux中的一些常用修改


1. 为所有用户永久修改终端名格式 如改为:[用户名@hostname 目录]$

修改方法:
vim /etc/bashrc
注释第41行内容[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ ",在该行下面添加如下
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\[\e[36m\][\[\e[31m\]\u@\[\e[36m\]\h \W]$ \[\e[m\]]\\$"

2. 常用别名
(1)/etc/profile.d/colorgrep.sh

alias grep='grep --color=auto' 2>/dev/null
alias egrep='egrep --color=auto' 2>/dev/null
alias fgrep='fgrep --color=auto' 2>/dev/null

(2)/etc/profile.d/colorls.sh

alias ll='ls -lh --color=auto' 2>/dev/null
alias l.='ls -d .* --color=auto' 2>/dev/null
alias ls='ls --color=auto' 2>/dev/null

(3)/etc/profile.d/vim.sh

alias vi >/dev/null 2>&1 || alias vi=vim

(4)/etc/profile.d/which2.sh

alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

(5)/root/.bashrc/rmi.sh

alias rm='rm -i'

三、元字符

0. ~   :home目录

1. `` 、 $()  存值,相当于python的 f"{}" 用法,且当``中有``时,取值会不正常,但是$()没影响

例:  `ls /home/test` 同 $(ls /home/test)  # 将ls /home/test命令的执行结果保存起来,一般用于变量赋值

2. $   :取值
(1)例: a = `ls /home/test`; echo $a  # 将ls /home/test命令的执行结果赋值给变量a,通过echo 打印变量a的值

(2)高级用法:$?   表示获取上一条命令的是否执行成功

	$? 的结果为0,表示上一条命令执行结果的真假,0表示结果为真,非0表示结果的假,shell编程时,常用
    
    # 如:((2>10))   echo $? 为 非0 ;  ((2<10))  echo $? 为 0

(3)$[]  可以用来做数字运算,如: echo $[1%10]  结果为1 ;echo $[1+1]  结果为2

(4)${}  格式化,同样作用的还有 "" ,作用都类似python3的f'{}'

(5)$HOME  表示当前用户的主目录

(6)$PATH  表示环境变量PATH的值

例:a = 10 ;echo ${a}00  # 1000 


3. []  :[]内的只取一个任意值
    
例:当前目录下有文件  1.txt 3.txt 33.txt a.txt c.txt Z.txt 

ls  [0-9].txt  # 1.txt 3.txt  同 ls  [0123456789].txt
ls  [0-9][0-9].txt  # 33.txt  同 ls  [0123456789][0123456789].txt
ls  [a-z].txt  # a.txt c.txt  a-z 的排序为 aZbBcC...zZ ,所以取不到 Z.txt

4. !   :取反

(1)
例:当前目录下有文件  1.txt 3.txt 33.txt a.txt c.txt Z.txt 
ls  [!0-9].txt  # 33.txt a.txt c.txt Z.txt

! ls  [0-9].txt  # 表示将 ls  [0-9].txt的执行状态取反,执行行打印结果为 33.txt a.txt c.txt Z.txt    ,再用 $? 查看,打印结果为 非0


(2)用 ! 执行历史命令

history 执行后,显示出执行过的历史命令

例:
history

...
454  ls /jtdata/products/
455  ls /mydata/
456  ls /mydata/docker/
457  ls /mydata/docker/mysql/
458  ls /mydata/docker/mysql/data/
...

!454  表示 执行历史命令的第454行命令


5. #   :表示注释,同python的 #

6. %   : 两个用法,(1)% 杀后台进程 jobs号;(2) 取余数,即 模除以

7. ^   :(1)取非,和 ! 类似;(2)替换   ^network^sshd^ 将network替换成sshd

8. &   :在后台执行

9. &&  :与运算

例: cd /home/test && mkdir test2  # 左边的命令执行成功才会继续执行右边的

10. *  :匹配任意长度字符串

11. -  :(1)减号;(2)区间号;(3)cd -  返回刚才的目录

12. | 管道符号,将 | 前面命令的输出当做后面命令的输入

13. || 或运算

例: pwd || echo 234  # /home/test ,表示在左边命令执行成功,右边的就不执行了,左边失败了,再执行右边的

14. =  :赋值,= 前后不能加空格,如: x=2

15. ==  :判断

16. []  :匹配中括号内之一

17. {}  :大括号内所有值,各取一遍,大括号内表示范围用 ..
例: touch {a..Z}.txt  # 创建 a到Z的txt空文件

18. \  :转译符,将关键字符 变为普通字符串,一般配合 "" 使用

例:
x = 1; echo $x  # 1
x = 1; echo "$x"  # 1
x = 1; echo "\$x"  # $x
x = 1; echo '$x'  # $x

19. ""  :软引用,作用都类似python3的f'{}'

20. ''  :硬引用,''内所有字符都无特殊意义,就是''内全部为普通的字符串,包括变量和关键字

21. ;  :分割多个命令,与 && 不同,这个会从左到右依次执行全部命令,在终端中和crontab中执行多条命令时,需要使用它,在脚本文件中无需使用它

22. :  :空命令,真值,可用于无限循环时的条件,如 while :

23. ?  :单个字符

24. <  :输入重定向,将右边内容当作输入,传入左边

25. >  :覆盖,将左边的内容覆盖到右边

26. >&  :当 >& 后面接文件时,表示将标准输出和标准错误输出重定向至文件,文件不存在会自动创建;当 >& 后面接文件描述符(0,1,2)时,表示将前面的文件描述符重定向至后面的文件描述符

26.1 &>file  :意思是把 标准输出 和 标准错误输出 都重定向到文件file中,文件不存在会自动创建

# shell中有三种标准的文件描述符:STDIN,STDOUT,STDERR,分别表示标准的输入,输出和错误输出,也可以分别用0,1,2来表示

# /dev/null  为黑洞文件,相当于垃圾站,可以把不用的东西扔里面,常用 &>/dev/null ,将不用的输出丢里面

# 例(2、3的作用一样):

(1)cat test 2>&1 >file :
错误输出到终端,标准输出被重定向到文件file

(2)cat test >file 2>&1 :
标准输出被重定向到文件file,然后错误输出也重定向到和标准输出一样,所以也错误输出到文件file

(3)cat test &>file :
把 标准输出 和 标准错误输出 都重定向到文件file中

27. >>  :追加,将左边的内容追加到右边

28. .  :当前目录

29. ..  :(1)当面目录的上一级目录;(2)大括号内表示范围

四、grep、sed、awk三种文本处理工具

  • 搭配正则一起使用,进行文并处理

1. grep 命令

(1)语法

  • 用于匹配全文中某个指定字符
语法:grep [options] '正则表达式' file 或者 grep [options] "正则表达式" file

options支持的参数:
-n  :显示行号
-o  :只显示匹配的内容
-q  :静默模式,没有任何输出,得用$?来判断执行成功没有,即有没有过滤到想要的内容
-r	:递归去找,一般用于查询指定目录下的所有文件的内容

-l  :如果匹配成功,则只将文件名打印出来,失败则不打印,通常-rl一起用,grep -rl 'root' /etc 
-A  :如果匹配成功,则将匹配行及其后n行一起打印出来
-B  :如果匹配成功,则将匹配行及其前n行一起打印出来
-C  :如果匹配成功,则将匹配行及其前后n行一起打印出来
--color  : 将匹配到的内容显示出颜色
-c  :如果匹配成功,则将匹配到的行数打印出来
-E  :等于egrep,扩展,简单来说就是,egrep支持更高级的正则语法
    
*****		所以我们只要记住,用grep 就用 grep -E 或者 egrep 就行		*****    

-i  :忽略大小写

-v  :取反,获取其他未匹配到的内容
-w:匹配单词,匹配内容的前后是空格 或前是空后是空格的 才属于单词


例:

[root@MiWiFi-R3-srv ~]# cat a.txt 
root123
ROot asdf
Root_123
rOOtss
root 123
[root@MiWiFi-R3-srv ~]# grep -i 'root' a.txt 
root123
ROot asdf
Root_123
rOOtss
root 123
[root@MiWiFi-R3-srv ~]# grep -w 'root' a.txt 
root 123

(2)正则

1. 普通正则
^ 以...开头
$ 以...结尾,$放在匹配内容之后
. 除了换行符以外的任意单个字符
* 前导字符的零个或多个
.* 所有字符
- 表示范围
[] 字符组内的任一字符
[^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)
^[^] 非字符组内的字符开头的行,^[^0-9] 表示 非0-9字符开头的行
[a-z] 小写字母
[A-Z] 大写字母
[a-Z] 小写和大写字母
[0-9] 数字
\< 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
\> 单词尾

\  转译后面的字符,让其变成普通字符,在转译 - 时,一般要放在正则表达式的开头或者结尾

2. 扩展正则(扩展正则需要使用 grep -E 或 egrep 才能支持)
? 前导字符零个或一个
+ 前导字符一个或多个
{n} 代表前面的字符有n个
{m,n} 代表前面的字符可以有 m到n个

2. sed 命令

  • 流编辑器,全称是stream editer,是以行为单位 来处理文本

(1)语法

语法:sed [options] 'commod' file 或者 sed [options] "commod" file

options支持的参数:
-n  :只显示匹配的内容
-e  :指定规则,可以同时用多个 -e 来指定多个规则
-i	:使用指定规则处理完文本之后直接修改源文件
-f	:使用指定文件中记录的正则表达式  如 sed -f /home/hsw/my_pattern.sed test.txt
-r	:支持扩展正则,简单来说就是,sed -r 支持更高级的正则语法
    
*****		所以我们只要记住,用sed 就用 sed -r 就行		*****
    
commod部分:

'[地址1,地址2] [函数] [参数(标记)]'  # 地址1 地址2 就是指定第m行到第n行,只写一个,就是指定处理第几行,不写定位就是是所有行

1. 定址的方法 (1)数字 (2)正则

(1)数字方法:
	十进制数
    1 第1行
    1,3 范围 从第一行到第三行
    2,+4 匹配行后若干行
    4,~3 从第四行到下一个3的倍数行
    2~3 第二行起每间隔三行的行
    $ 尾行
    1! 除了第一行以外的行
    
(2)正则方法:
正则必须用//包裹起来,来匹配要进行操作的某一行
***扩展正则需要用 -r 参数***

2. 函数
增删改
a 追加
c 覆盖整行
i 前插
d 删除
输入输出
p 打印匹配的行 一般和 -n 参数连用,以屏蔽默认输出
r 从文件中读入
w 写入到文件中
s 字符替换,默认替换每行第一个,替换一次,使用 g 指定全部替换(最常用)

3. 参数(标记)
g   整行内全部执行
\n	n为正整数,配合 ()使用,表示保留第几个()匹配的内容,且有多个\n时,会根据 \n的顺序排列匹配的内容,\n 最多写9个

例:
sed -rn '1p' test.txt  # 打印第一行
sed -rn '/^root/p' test.txt  # 打印以root开头的行
sed -r '3c 123456' test.txt  # 将第三行替换成 123456
sed -r '1 d; 3 d' test.txt  # 删除第一行和第三行
sed -r '1,3 d' test.txt  # 删除第一行到第三行
sed -rn '1!p' test.txt  # 打印除第一行之外的行
sed -rn '/sb/p' test.txt  # 打印含有sb的行

sed -r 's/sb/SB/' test.txt  # 把所有行里的第一个sb换成SB
sed -r 's/sb/SB/g' test.txt  # 把所有行里的所有sb换成SB
sed -r '/^[0-9][a-Z]+b$/ s/sb/SB/g' test.txt  # 将以数字开头,数字后跟字母的,最后以b结尾的行匹配出来,将其中的sb全部替换成SB

sed -r 's/([^a-Z])([a-Z]+)$/ \1/g' test.txt  # 将所有行的行尾是单词的单词去掉。这里\1 表示 保留 ([^a-Z]) 匹配到的内容

sed -r 's/^([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)/ \3\2\1\4/g' test.txt  # 将行首的单词与第二个单词互换位置

(2)正则(同上面的 grep正则)

3. awk 命令

  • 用于处理有固定格式的文本

(1)语法

语法:awk [options] 'commands' file

options支持的参数:

-F	定义字段分割符,默认的分割符是连续的空格或制表符,类似python的字符串的split方法
NF	表示当前行的分割域的数量
NR 表示当前行的行号,可以用来定址(指定匹配第几行)
$n	n为0开始的整数,用$1,$2,$3等的顺序表示每行分割的各列不同域,$0 表示取所有分割的域;$NF 表示最后一份
-v 定义变量并赋值 也可以借用次方式从shell变量中引入

commod部分:
'[定址][操作]'

1. 定址的方法 (1)NR (2)正则
(1)NR  NR=2、NR>=2 && NR<=5、NR<=2 || NR>=5,不写NR默认所有行

(2)正则方法:
正则必须用//包裹起来,来匹配要进行操作的某一行

2. 操作

要进行的操作,写在{}中,一般同 $n 连用


例:
awk -F: '{print $1,$3,NF,$NF,NR}' test1.txt  # 以 : 分割每一行,打印出每行第1段、第三段、总共分了几份、最后一段、当前是第几行
    
awk -F: 'NR=2{print $1,"我是临时添加的内容",$3}' test1.txt  # 以 : 分割第二行,打印结果为:第一段 我是临时添加的内容 第三段   
    
awk -F: 'NR>=2 && NR<=5{print $1}' test1.txt  # 以 : 分割第二到五行,打印第2到第5行的第一段内容
    
awk -F: 'NR<=2 || NR>=5{print $1}' test1.txt  # 以 : 分割第1、2行和第5行及第5行之后的,打印第一段内容
    
awk -F: '/nologin$/{print $1}' test1.txt  # 以 : 分割 nologin结尾的行,打印出第一段

awk -F: '/^r.*t$/ {print $3}' test1.txt  # 以 : 分割 r开头t结尾的行,打印第三段   
    
awk -F: '$1~/^r.*t$/ {print $3}' test1.txt  # 以 : 分割 第一段是r开头t结尾的行,打印第三段    

awk -F: '$1=="root"/^r.*t$/ {print $3}' test1.txt  # 以 : 分割 第一段是root的行,打印第三段    
awk -F: '$3>=5/^r.*t$/ {print $3}' test1.txt  # 以 : 分割 第3段的值大于等于5的行,打印第三段 
    
a=7  # 定义一个变量   
awk -v x=$a -F: '$3 >= x {print $2}' test1.txt  # 将变量传入匹配规则,以 : 分割 第3段的值大于等于7的行,打印第2段

(2)正则(同上面的 grep正则)

4. 其他命令补充

(1)sort

语法:sort [options] file  # 对行进行排序

options的参数:

-r:以相反的顺序排序
-n:按数字顺序排序
-f:忽略大小写
-u:仅显示唯一的行
-t:指定字段分隔符
-k:按指定字段进行排序
-c:检查文件是否已经按照指定的顺序排序
-o:将排序结果输出到指定文件中

(2)uniq

语法:uniq [options] file  # 行去重

options的参数: 

-c: 显示每行重复出现的次数。
-d: 仅显示重复行。
-i: 忽略大小写。
-u: 仅显示不重复的行。
-f n: 忽略前n个字段。
-s n: 忽略前n个字符。
--help: 显示帮助信息。
--version: 显示版本信息

(3)cut

语法: cut  [options] 'commods' file  # 切割,相当于简化版的awk

[options]参数:

-c	按字符位置提取文本列
-d  功能同awk的 -F
-fn  功能同awk的$n  ,但是其中的分割符,也算是一位

例:

cat test.txt  # 结果:
asdf:111222:666
dsfdf:3333555:777

cut -d: -f1 test.txt  #  以 : 分割,保留第一部分,结果:
asdf
dsfdf

cut -d: -f1,3 test.txt  # 以 : 分割,保留第一到第三部分,结果:
asdf:111222
dsfdf:3333555
    
# 要提取文件example.txt中的第1到第5个字符    
cut -c 1-5 example.txt

# 要提取文件example.txt中以逗号分隔的第2个字段
cut -d ',' -f 2 example.txt

(4)head

语法:head [options] file  # 用于显示文件的开头几行内容,默认情况下显示文件的前10行

options的参数:(这些参数可以根据需要进行组合使用)

-n:指定显示文件的前n行内容,例如head -n 5 file.txt将显示file.txt文件的前5行内容。
-c:指定显示文件的前n个字节内容,例如head -c 20 file.txt将显示file.txt文件的前20个字节内容。
-q:当同时处理多个文件时,不显示文件名。
-v:当同时处理多个文件时,显示文件名。
-z:在每个文件之间用null字符分隔,用于与xargs命令配合使用

(5)tail

语法:tail [options] file  # 用于显示文件的末尾内容,默认情况下显示文件的末尾10行

options的参数:(这些参数可以根据需要进行组合使用)

-f:实时监控文件内容的变化,类似于“跟踪”文件。
-n:指定要显示的行数。
-c:指定要显示的字节数。
-q:不显示文件名。
-v:始终显示文件名。
--pid=PID:与-f选项一起使用,指定要监控的进程ID。
--retry:与-f选项一起使用,如果文件不存在或无法打开,则不断重试

(6)more

语法:more [options] file  # 用来逐页显示文本文件内容的命令,q 退出查看

options的参数:(这些参数可以根据需要进行组合使用)

-d:显示每一页的内容之前先清除屏幕;
-c:不进行滚屏操作,而是每次只清屏并显示新的一屏内容;
-p:指定每页显示的行数,默认为 24 行;
-s:将连续的空行显示为一行;
-u:禁止对文件内容进行下划线处理;
-w:将输出内容写入文件中,而不是直接输出到终端

例:
more -d -p 20 file.txt  # 将会以每页 20 行的方式逐页显示文件 file.txt 的内容,并在每一页显示之前清屏

(7)wc

语法:wc [-clw][--help][--version][文件...]  # wc命令用于计算字数

options的参数:

-c或--bytes或--chars 只显示Bytes数
-l或--lines 显示行数
-w或--words 只显示字数
--help 在线帮助
--version 显示版本信息

 -L 或 --max-line-length:统计最长行的长度

五、变量

1. 变量命名规则

同python规则差不多,以字母或下划线开头,剩下的部分可以是:字母、数字、下划线.

最好遵循下述规范:

1.以字母开头
2.使用中划线或者下划线做单词的连接
3.同类型的用数字区分
4.对于文件最好加上拓展名

2. 变量的用法

(1)查看变量

使用 set 和 env 命令

set	 显示所有变量,包括已定义函数的函数名
env  只显示环境变量

(2)常用系统变量

PATH
PWD
LANG
HOME
HISTSIZE
PS1
IFS

(3)变量的赋值

语法:变量名=VALUE  # = 两边不能有空格

(4)变量的取值

语法:$变量名

x=1
$x  # 取变量x的值

(5)变量的打印

语法:echo $变量名  # echo 相当于 python中的 print 方法

(6)变量的删除

语法:unset 变量名

六、运算符

注意:在shell中,所有的写法都是字符串,只有加上计算器方法,才能实现运算,最常用的计算器方法就是 ((...)) ,... 为我们要计算的表达式。还有其他计算器方法,如$[] 、expr ,不好用,所以这里不做介绍了

1. 基础运算符
+	-	*	/	%

2. 关系运算符,与 (()) 连用,作用同python的 f"{}"

<	>	<=	>=	==	!=	&&	||

3. 赋值运算符,与 (()) 连用,作用同python的 f"{}"

=	+=	*=	/=	%=  ++ --

# 例:
x=2
((x>3)) ((x%3)) 

# 例:
x=1
((x+=1)) ((x=x+1)) # 都实现 x=x+1 

x=$x+1  # 注意:将 x 赋值为 '1+1' 这样的的字符串

七、shell中的判断方法(测试)

  • 可以用 man test 命令查看test的所有方法
  • 可以用test命令,也可以用 [] 、[[]]、 (())[] [[]]内两边必须要空格,且运算符也必须要空格,所以当书写判断时,记住每个”单词“两边全都空格就行

1. 文件、目录判断

语法:test [option] dir、file

option参数:
-d	存在且是目录
-e  文件存在
-f  文件存在且是一个普通文件(非软硬链接)
-h  文件存在且是链接文件
-r  文件存在且当前用户有读权限
-w  文件存在且当前用户有写权限
-x  文件存在且当前用户有执行权限
-s  文件存在且是非空文件

# 例:再用 $? ,获取判断结果,判断当前目录下 test1.txt 文件是否存在
test -e test1.txt
[ -e test1.txt ]
[[ -e test1.txt ]]
(( -e test1.txt ))

2. 字符串判断

语法:test 字符串1 [option] 字符串2

option参数:

=  两个字符串相等
!=  两个字符串不相等
-z  空串
-n  非空串

# 例:
var1='abc'
var2='123'

[ $var1 = $var2 ]  # [] 内两边必须要空格
test $var1 = $var2

# ********  注意,字符串判断的坑  ********
当字符串中存在空格时,直接比较,会报错:参数太多

需要这样书写,给变量使用软引用的 ""

var1='abc 123'
var2='123'

[ "$var1" = "$var2" ]  # 正确书写格式 
[ "$var1" = 'abc 123' ]  # 正确书写格式 

3. 数字判断

语法:test 数字1 [option] 数字2

# 注意,数字判断  test 和 [] 内 不能用 <	>	<=	>=	==	!= ,只能用下面的这些代替

option参数:

-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于

# [[]]、  (()) 内可以正常使用 <	>	<=	>=	==	!=


# 例:
test 11 -gt 10
[ 11 -gt 10 ]  # [] 内两边必须要空格
((11>10))
[[ 11 > 10 ]]  # [[]] 内两边必须要空格,且 > 两边也要空格

八、向脚本传参

1. 接收外部参数

cat test.sh

#!/bin/bash

echo $0
echo $1
echo $2
echo $3
echo $4
echo $5
echo ${11}
echo '$$' $$
echo '$*' $*
echo '$@' $@
echo '$#' $#
echo '$?' $?

sh test.sh 1 2 3 4 5 6 7 8 9 10 11

# 输出:
./test.sh
1
2
3
4
5
11
$$ 14312 
$* 1 2 3 4 5 6 7 8 9 10 11
$@ 1 2 3 4 5 6 7 8 9 10 11
$# 11
$? 0

# 按空格区分参数的位置,且大于等于10个参数时要用${10},${11},${12}...

$0 脚本文件本身($0=./xx.sh)
$$ 为执行当前脚本后的pid号
$* 为接收的全部参数
$@ 为接收的全部参数,和$*有点区别,但是基本很少用到这个区别
$# 为接收的最后一个参数

2. 接收”输入“参数

# read 命令和python的input方法功能类似,用于接收外部输入的内容
# read 会自动去掉输入内容的两边空格

语法:
read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

常用的选项包括:

-p:指定读取时的提示信息;
-t:指定读取超时时间;
-d:指定读取时的分隔符;
-a:将读取的文本存储到数组中

例:

# 读取用户输入的姓名并存储到变量name中
read -p "请输入您的姓名:" name

九、流程控制

  • 注意,shell里面没有缩进子代码的概念,全靠语法关键字来辨别,导致我们的代码看起来很吃力,所以需要我们人为手动去给它书写格式。一般会 空格4次 再书写子代码,尽量不要用Tab去缩进
  • #!/bin/bash就是告诉系统,用什么解释器解释代码,一般脚本文件都要在首行加上这个

1. if判断

(1)语法

1. if
if 条件
then
        code
fi  


2. if ... else

if 条件1
then
        code
else 条件2
    code
fi    


3. if ... elif ... else
      
if 条件1
then
    code
elif 条件2  
then
     code
elif 条件3  
then
     code   
else 条件4
    code
fi  

(2)实例

1. 判断指定进程是否存在

# 编写一个判断nginx进程是否存在,不存在则启动nginx的脚本


vi check_nginx.sh


#!/bin/bash

ps aux |grep nginx |grep -v 'grep'
if [ $? -ne 0 ]
then
    systemctl start nginx
fi        

:wq


# 其中:
# #!/bin/bash 就是告诉系统,用什么解释器解释代码,一般脚本文件都要在首行加上这个
grep -v 'grep' 是去掉 grep本身的进程

2. while循环

(1)语法

while 条件
do
    code
done


# 与循环组合使用的关键字:
exit  # 退出整个程序 
break  # 退出本层循环
continue  # 退出本次循环

(2)实例

1. 实时监控内存变化

#!/bin/bash

while :
do
    free
    sleep 0.5
    clear
done

# 冒号是空命令,真值
# #!/bin/bash 就是告诉系统,用什么解释器解释代码,一般脚本文件都要在首行加上这个


2. 互相赋值

#!/bin/bash

var1=AAA
var2=BBB
var3=CCC
while :
do
    clear
    echo -e "A:${var1}\nB:${var2}\nC:${var3}"
    temp=$var1
    var1=$var2
    var2=$var3
    var3=$temp
    sleep 1
done

# -e 是使 \n 有意义,变为换行符,没有 -e 就是普通的字符串


3. 条件实现有限循环

count = 1
while [[ $count <= 10 ]]
do
    echo $count
    ((count++))
done    


4. exit关键字 实现 退出程序

#!/bin/bash

while :
do
    read -p 'please input your username: ' username
    read -p 'please input your password: ' psd
    if [ $username = 'hsw' ] && [ $psd = 'hsw123456' ]
    then
        echo 'welcome hsw'
        exit
    else
        echo 'username or password is error'
    fi
done

echo '我是分隔线'

# exit的作用是,退出整个程序。虽然也实现退出循环了,但是exit后面的代码都不会执行了。比如这里的当if判断成功, 我是分隔线 就不会打印出来了


5. break关键字 实现 退出本层循环

#!/bin/bash

while :
do
    read -p 'please input your username: ' username
    read -p 'please input your password: ' psd
    if [ $username = 'hsw' ] && [ $psd = 'hsw123456' ]
    then
        echo 'welcome hsw'
        break
    else
        echo 'username or password is error'
    fi
done

echo '我是分隔线'

# break 只是跳出本层循环,不会终止程序,作用和python里的break一样,最后会正常打印 我是分隔线


6. continue关键字 实现 退出本次循环

#!/bin/bash

while :
do
    read -p 'please input your username: ' username
    read -p 'please input your password: ' psd
    
    if [ -z $username ] || [ -z $psd ]
	then
	    echo '用户名或密码不能为空'
    	continue

    elif [ $username = 'hsw' ] && [ $psd = 'hsw123456' ]
    then
        echo 'welcome hsw'
        break
        
    else
        echo 'username or password is error'
    fi
done

echo '我是分隔线'

# continue 只是跳出本次循环,不会终止程序,不会退出本层循环,作用和python里的continue一样,最后会正常打印 我是分隔线


7. 嵌套循环

#!/bin/bash

while :
do
    read -p 'please input your username: ' username
    read -p 'please input your password: ' psd
    
    if [ -z $username ] || [ -z $psd ]
	then
	    echo '用户名或密码不能为空'
    	continue

    elif [ $username = 'hsw' ] && [ $psd = 'hsw123456' ]
    then
        echo 'welcome hsw'
        while :
        do
            read -p 'please input your cmd: ' cmd
            if [ "$cmd" = 'quit' ]
            then
                break
            fi
            $cmd
        done
        
    elif [ $username = 'quit' ] || [ $psd = 'quit' ]
    then
        echo 'bye bye!!'
        break
        
    else
        echo 'username or password is error'
    fi
done

echo '我是分隔线'

4. for循环

(1)语法

for ... in ...
do
    code
done 


# 与循环组合使用的关键字(作用同while循环里的):
exit  # 退出整个程序 
break  # 退出本层循环
continue  # 退出本次循环

(2)实例

1. 挨个打印1到10

#!/bin/bash

for i in {1..10}
do
    echo $i
done


2. 循环 一条命令的结果

#!/bin/bash

for i in `ls /home`
do 
    echo $i
done    


3. 简单实现 ping 一段范围的ip

#!/bin/bash

for i in {1...253}
do
     ping -c1 192.168.16.$i >& /dev/null
     
     if (( $? == 0 ))
     then
         echo "192.168.16.$i is available"
     else
     then
         echo "192.168.16.$i is unavailable"
     fi
done     

#  >& 为重定向,/dev/null 为Linux的黑洞文件,可以简单理解为垃圾站

5. case判断

(1)语法

  • case方法不常用
case ... in 
条件1)
code1
;;
条件2)
code2
;;
条件3)
code3
;;
*)
code4
esac

# 作用相当于if...elif... else...

# ;; 为结束本次判断
# * 除了之前的情况,其他所有情况,相当于else

(2)实例

#!/bin/bash

read -p "username: " uname

case $uname in 
root)
echo "welcome $uname"
;;
seker)
echo "welcome $uname"
;;
default)
echo "welcome $uname"
;;
*)
echo "no user $uname"
esac

十、函数

1. 语法

1. 定义函数

方式一:function 函数名 (){code}

方式二:函数名 () {code}

2. 查看函数

可以终端输入 set  命令查看已定义函数的函数名

3. 调用函数
直接书写 函数名 即可

4. shell里函数不支持传参,函数外部参数都是直接在函数里调用

5. shell函数的return只能返回0~255的整数类型。其中,0表示函数执行成功,其他数值则表示函数执行失败或出现异常情况,可以通过$?变量来获取函数的返回值。shell的函数方法的return一般没啥应用场景

2. 实例

1. 简单定义函数并调用

#!/bin/bash

function hello(){  # 声明函数
echo "Hello!"  # 函数的主体
}  # 函数结束

hello  # 调用函数,输出"Hello!"


2. 使用外部参数

#!/bin/bash

function hello2(){
	sum=$(($1 + $2))
    echo "The sum of $1 and $2 is: $sum"
}

hello2 10 20  # 输出:The sum of 10 and 20 is: 30


3. 函数里调用函数

#!/bin/bash

function hello1(){
echo "Hello1!"
}

function hello2(){
echo "Hello2!"

hello1

}

hello2  # 调用函数


4. 函数的return

#!/bin/bash

function my_add() {
    local sum=$(($1 + $2))
    return $sum
}

my_add 10 20
echo "The result is: $?"

# my_add函数将两个参数相加并将结果赋值给变量sum,然后通过return语句将sum作为函数的返回值。在调用add函数后,使用$?变量获取函数的返回值并输出

4. 调用其他的.sh文件中的函数

# 假设有一个名为functions.sh的脚本文件,其中定义了一个名为my_function的函数。要在另一个脚本文件functions2.sh中调用该函数

cat functions2.sh

# cat 结果
source /路径/functions.sh
my_function


5. 同步时间

#!/bin/bash
function sync_time(){
    . /etc/profile
    /sbin/ntpdate 10.0.74.71
    /usr/sbin/hwclock -w
}

十一、计划任务

1. 什么是计划任务

  • 作用:到了预定的时间就会自动在后台执行指定的任务

  • 一般Linux系统会自动安装好,并且会开机自启crond服务

    • # crond服务相关的软件包
      
      使用如下命令进行查看:
      rpm -qa |grep cron
      
      
      cronie-anacron-1.4.11-14.el7.x86_64
      crontabs-1.11-6.20121102git.el7.noarch
      cronie-1.4.11-14.el7.x86_64
      
      # 这些包在最小化安装系统时就已经安装了,并且会开机自启动crond服务,并为我们提供好编写计划任务的crontab命令
      
  • 计划任务分为两类:系统级和用户级

    • 无论是系统级还是用户级的cron计划都是文本文件,系统的计划文件存放在/etc/crontab路径下。用户的计划文件放在/var/spool/cron/用户名,不管是哪一种,都可以满足我们定制计划任务的需求
  • root用户可以直接对文件进行修改来编写计划任务也可以使用 crontab -e命令,而普通用户只能使用后者。除此之外,系统crontab文件中任务的定义也有所不同,在前五个部分之后插入了一个“用户”部分

2. 计划任务的语法

1. 语法
系统级的语法:
* * * * * username command

普通用户的语法(包括root):
* * * * * command


.---------------- minute (0 - 59)
| .------------- hour (0 - 23)
| | .---------- day of month (1 - 31)
| | | .------- month (1 - 12) OR jan,feb,mar,apr ...
| | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
| | | | |
* * * * * user-name command


* * * * * user-name command 各列的意思

第1列,表示分钟1~59 每分钟用*或者 */1表示
第2列,表示小时1~23(0表示0点),每小时用*
第3列,表示日期1~31,每天用*
第4列,表示月份1~12,每月用*
第5列,表示星期0~6(0表示星期天),每周天用*
第6列,表示什么用户的计划任务,系统级才有该列
第7列,要运行的命令,要执行的脚本文件最好书写绝对路径


2. crontab 命令,常用第二种

第一种:crontab [-u <用户名称>][配置文件] 

第一种:crontab [-u <用户名称>][-elru]

-elr参数:
-e  编辑该用户的计划任务
-l  列出该用户的计划任务
-r  删除该用户的计划任务
-u <用户名称>  指定要设定计划任务的用户名称,不加 -u就是默认当前用户

3. 实例

# 清理7天之前的日志
00  23  * * * /usr/bin/rm -f `/usr/bin/find /opt/var/log/ -type f -mtime +7`

# 每天凌晨2:30执行 jtdatadel.sh 脚本
30 2 * * * /opt/project/jtdata_del/jtdatadel.sh >/dev/null 2>&1

# 每分钟执行一下rainfall.py,并将日志输出到run.log
*  *  *  *  * /jtnas/opt/rainfall/rainfall.py >> /jtnas/opt/rainfall/run.log 2>&1

# 每月1、10、22日的4 : 45重启apache
45 4 1,10,22 * * /usr/local/etc/rc.d/apache restart 

# 每周六、周日的1 : 10重启apache
10 1 * * 6,0 /usr/local/etc/rc.d/apache restart 

# 每天18 : 00至23 : 00之间每隔30分钟重启apache
0,30 18-23 * * * /usr/local/etc/rc.d/apache restart 

# 每半小时同步一下时间
*/30 * * * * /usr/sbin/ntpdate 210.72.145.44 

# 每月的4号与每周一到周三的11点重启lighttpd
0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/34742.html

(0)
上一篇 2024-01-26 20:26
下一篇 2024-02-01 16:33

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信