Erlo

linux-bash基础入门

2022-05-15 22:30:02 发布   136 浏览  
页面报错/反馈
收藏 点赞

一、bash 基础

1.变量累加

name=${name}yes  #以此例较佳!
echo $a$b

2.上个执行指令的回传值 echo $?

[dmtsai@study ~]# echo $SHELL
/bin/bash #可顺利显示!没有错误!
[dmtsai@study ~]# echo $?
0 <#因为没问题,所以回传值为 0
[dmtsai@study ~]# 12name=VBird
bash: 12name=VBird: command not found... #发生错误了!bash回报有问题
[dmtsai@study ~]# echo $?
127 #因为有问题,回传错误代码(非为0)

*使用?判断变量值
[root@localhost ddd]# unset str
[root@localhost ddd]# str=string1
[root@localhost ddd]# echo ${str}
string1				#此时能读到
[root@localhost ddd]# unset str
[root@localhost ddd]# echo ${str?无此变量}  #判断是否有str,有则打印没有则输出;;使用echo ${str:-"不存在"}
-bash: str: 无此变量

#echo;在 Linux 下用 > 和 >> 表示,> 表示输出到一个新文件中,而 >> 则表示输出到 现有文件的末尾。

3.键盘读取read

[dmtsai@study ~]# read [-spt] variable
选项与参数:
-p :后面可以接提示字符!
-t :后面可以接等待的“秒数!”这个比较有趣~不会一直等待使用者啦!
-s :隐藏键盘输入
#eg:
[root@localhost ~]# read -p"input contents" -t10 
input contents  #-t默认30秒

4.declare / typeset

* declare/typeset
[dmtsai@study ~]# declare [-aixr] variable
选项与参数:
-a :将后面名为 variable 的变量定义成为阵列 (array) 类型
-i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将变量设置成为 readonly 类型,该变量不可被更改内容,也不能 unset
范例一:让变量 sum 进行 100+300+50 的加总结果
[dmtsai@study ~]# sum=100+300+50
[dmtsai@study ~]# echo ${sum}
100+300+50 以文本打印
[dmtsai@study ~]# declare -i sum=100+300+50
[dmtsai@study ~]# echo ${sum}
450 #-i以数字计算

5.与文件系统及程序的限制关系: ulimit

#文件太大无法在系统生成的问题:1.检查ulimit 2.使用split进行文件分区 大文件分成小文件
[dmtsai@study ~]# ulimit [-SHacdfltu] [配额]
选项与参数:
-H :hard limit ,严格的设置,必定不能超过这个设置的数值;
-S :soft limit ,警告的设置,可以超过这个设置值,但是若超过则有警告讯息。
	在设置上,通常 soft 会比 hard 小,举例来说,soft 可设置为 80 而 hard
	设置为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时,
	系统会有警告讯息通知你!
-a :后面不接任何选项与参数,可列出所有的限制额度;
-c :当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),
这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。
-f :此 shell 可以创建的最大文件大小(一般可能设置为 2GB)单位为 KBytes
-d :程序可使用的最大断裂内存(segment)容量;
-l :可用于锁定 (lock) 的内存量
-t :可使用的最大 CPU 时间 (单位为秒)
-u :单一使用者可以使用的最大程序(process)数量。

6.自定义命名 alias/unalias

alias lm='ls -al | less' #文件多的情况下,可以分页显示*,也可以使用关键字搜索;但是*匹配也可以

7.history/HISTSIZE

history如何显示时间、IP等信息

[root@localhost a5_dtx]# HISTSIZE=5    #可以登出重新写入.bash_profile 或者用history -w强制写入
[root@localhost a5_dtx]# echo ${HISTSIZE}
5
[root@localhost a5_dtx]# history 
  700  echo ${HISTSIZE}
  701  history 
  702  HISTSIZE=5
  703  echo ${HISTSIZE}
  704  history

8.关于进程被挂起

jobs -l #查看挂起进程
fg 关键字 #唤起进程,或者fg [NUM]

9.万用字符(wildcard)与特殊符号

10.命令执行的判断依据: ; , &&, ||

* cmd1;cmd2 不判断直接执行
* cmd1&&cmd2 指令1正确($?=0)的情况下执行指令2;批量执行脚本神器 超级方便
* cmd1||cmd2 指令1正确则不执行指令2,指令1不正确则执行指令2
ls /etc/profile111 && echo "exist" || echo "not exist" && touch /etc/profile111

11.统计行数、字符等:wc

[dmtsai@study ~]# wc [-lwm]
选项与参数:
-l :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;
#eg1: 检测是否存在mysql进程,存在返回0,不存在返回1
[root@localhost ddd]# ps aux|grep mysql|grep -v 'color' && echo "process mysql exist" || echo "process mysql not exist"
process mysql not exist
#eg2:检测是否存在mysql进程,存在返回1,不存在返回0
[root@localhost ddd]# ps aux|grep mysql|grep -v 'color'|wc -l && echo "process mysql not exist" || echo "process mysql exist"
0
process mysql exist

12.快捷键补充

* ctrl+r:搜索历史输入命令 避免history的低效率
* ctrl+u/k:向前/后 删除指令串
* ctrl+a/e:代替home/end键,到指令串的最前或者最后
* ctrl+s/q:冻结/解冻前端

13.cut指令

[dmtsai@study ~]# cut -d'分隔字符' -f fields filename#用于有特定分隔字符
[dmtsai@study ~]# cut -c 字符区间 filename  #用于排列整齐的讯息 对列处理
选项与参数:
-d :后面接分隔字符。与 -f 一起使用;
-f :依据 -d 的分隔字符将一段讯息分区成为数段,用 -f 取出第几段的意思;
-c :以字符 (characters) 的单位取出固定字符区间;
#eg:
[root@localhost ddd]# cat test.txt 
1:2:3:4:5:6:a:b:c:d:e:f
[root@localhost ddd]# cat test.txt | cut -d ':' -f 2,3
2:3 #以:为分隔符,取出第2至3段;;;或者cut filename
[root@localhost ddd]# cat test.txt | cut -c 2-5
:2:3  #取出第2到5个的字符;2-表示取出第二个以及之后的字符

14.字符转换命令: tr, col, join, paste, expand

# 目前使用频率低 仅做记录
[dmtsai@study ~]# tr [-ds] SET1 ...
选项与参数:
-d :删除讯息当中的 SET1 这个字串;
-s :取代掉重复的字符!

[dmtsai@study ~]# col [-xb]
选项与参数:
-x :将 tab 键转换成对等的空白键

[dmtsai@study ~]# join [-ti12] file1 file2
选项与参数:
-t :join 默认以空白字符分隔数据,并且比对“第一个字段”的数据,
如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个!
-i :忽略大小写的差异;
-1 :这个是数字的 1 ,代表“第一个文件要用那个字段来分析”的意思;
-2 :代表“第二个文件要用那个字段来分析”的意思。

[dmtsai@study ~]# paste [-d] file1 file2
选项与参数:
-d :后面可以接分隔字符。默认是以 [tab] 来分隔的!
- :如果 file 部分写成 - ,表示来自 standard input 的数据的意思。

[dmtsai@study ~]# expand [-t] file
选项与参数:
-t :后面可以接数字。一般来说,一个 tab 按键可以用 8 个空白键取代。
我们也可以自行定义一个 [tab] 按键代表多少个字符呢!

[dmtsai@study ~]# split [-bl] file PREFIX
选项与参数:
-b :后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分区。
PREFIX :代表前置字符的意思,可作为分区文件的前导文字。

15.管线命令(pipe)

那么如果这群数据必需要经过几道手续之后才能得到我们所想要的格式,应该如何来设置?
这就牵涉到管线命令的问题了 (pipe) ,管线命令使用的是“ | ”这个界定符号!
其实这个管线命令“ | ”仅能处理经由前面一个指令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力。那么整体的管线命令可以使用下图表示

16.参数代换: xargs

# 很多指令其实并不支持管线命令,可使用xargs以指引stdin
[dmtsai@study ~]# xargs [-0epn] command
选项与参数:
-0 :如果输入的 stdin 含有特殊字符,例如 `, , 空白键等等字符时,这个 -0 参数
可以将他还原成一般字符。这个参数可以用于特殊状态喔!
-e :这个是 EOF (end of file) 的意思。后面可以接一个字串,当 xargs 分析到这个字串时,
就会停止继续工作!
-p :在执行每个指令的 argument 时,都会询问使用者的意思;
-n :后面接次数,每次 command 指令执行时,要使用几个参数的意思。
当 xargs 后面没有接任何的指令时,默认是以 echo 来进行输出喔!
ps -ef | grep java | grep -v "grep" | awk '{print $2}' | xargs kill 

17.关于减号的用途:-

[root@localhost ddd]# tar zcvf - test.txt | tar zxvf - mysql 
#将test.txt打包,但是不是记录到文件 而是传送到stdout;经过管线之后 把tar zcvf - test.txt传送给tar zxvf -;这里的-,就是取用前面一个指令的stdout

18.数据流重导向

(1)指令执行过程的数据传输情况

(2)standard output 与 standard error output
标准输出指的是“指令执行所回传的正确的讯息”,而标准错误输出可理解为“指令执行失败后,所回传的错误讯息”;用数据重导向可以将standard output (简称 stdout) 与 standard error output (简称 stderr)分别传送到其他的文件或设备
1. 标准输入  (stdin) :代码为 0 ,使用  或 >> ;
3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;

ll / > ~/rootfile  将根目录下的目录写进rootfile这个文件;或者用1>

1> :以覆盖的方法将“正确的数据”输出到指定的文件或设备上;
1>>:以累加的方法将“正确的数据”输出到指定的文件或设备上;
2> :以覆盖的方法将“错误的数据”输出到指定的文件或设备上;
2>>:以累加的方法将“错误的数据”输出到指定的文件或设备上;
#将stdout和stderr存到不同的文件;屏幕不会打印信息
find /home -name .bashrc > list_right 2> list_error
(3)/dev/null设备和特殊写法
#只显示正确信息
find /home -name .bashrc 2> /dev/null

#怎么把正确和错误信息同时写进文件
find /home -name .bashrc >list 2>list	#错误 可能会交叉写入该文件内,造成次序的错乱,虽文件会产生 但是里面的数据排列是乱的
find /home -name .bashrc >list 2>&1 #正确 对于空文件就>/dev/null 2>&1 前半部分正常输出,2表示stderr 表示2的输出重定向等同于1
find /home -name .bashrc >list #正确

#>/dev/null 2>&1 将错误信息重定向到1 ;;  1>&2将正确信息重定向到2
(4)standard input
将原本由键盘输入的数据,改由文件内容来取代

#由于加入>在cat后,所以那个catfile会被主动的创建,文件内容即键盘输入;使用C+D结束;也可以用cat >>catfile进行键盘累加
cat > catfile  

#用stdin取代键盘的输入以创建新文件的简单流程
cat > catfile  catfile > aa.msg >追加 >覆盖
EOF

二、正则表达式(Regular Expression)与文件格式化处理

揭开正则表达式的神秘面纱

正则表达式30分钟入门教程

正则在线校验1 正则在线校验2(多使用这两个网址练习)

1.grep的一些进阶

-c 统计关键字次数;也可以用|wc -l代替
-v 排除相关行
-w 只显示全字符合的列
-i 忽略字符大小写的差别
-o 只输出文件中匹配到的部分
-n 显示列号
--color 关键字显示颜色;实际grep已经用alias设置为‘grep --color=auto’

2.正则相关

* 利用[]搜索集合字符 
* 利用''搜寻特定字符
#eg: grep -n '[^g]oo' regular_express.txt   ==搜寻oo且oo前面没有g;但比如gooole 是符合搜索条件的
	 grep -n '[^a-z]oo' regular_express.txt
* 行首与行尾字符 ^ $ 
	^ -1.表示否定
		[^a]表示“匹配除了a的任意字符”。
		[^a-zA-Z0-9]表示“找到一个非字母也非数字的字符”。
		[^abc]表示“找到一个插入符或者a或者b或者c”。用[/abc]也Ok 但是需避免转义字符?
	-2.表示限定开头
		/[(^s+)(s+$)]/g
		(^cat)$
		(^cat$)
		^(cat)$
		^(cat$)
#eg:grep -n '^$' filename  ==打印空白行
#eg:grep -v '#' /etc/rsyslog.conf | grep -v '^$' 
* 任意一个字符. 与重复字符*(!!!和万用字符的含义不一样)
#text: "Open Source" is a good mechanism to develop programs.
#重点:“o”代表的是:“拥有空字符或一个 o 以上的字符”,因此'o*'会把打印所有字符;oo*:第一个肯定存在,第二个是可有可无的多个o,所有凡是含有o,oo,ooo等都会	打印出来
#eg:grep -n 'g..d' regular_express.txt  ==搜索g和d之间是两个字符条件的
#eg:grep -n 'g.*g' regular_express.txt  ==.* 就代表零个或多个任意字符,匹配开头是g结尾也是g的字符串
#eg:grep -n 'g*g' regular_express.txt   ==代表匹配一个以及多个连续的g
* 限定连续 RE 字符范围 {}    
	-1.若为 {n} 则是连续n个的前一个RE字符
	-2.若是 {n,} 则是连续n个以上的前一个RE字符
#{ 与 } 的符号在 shell 是有特殊意义(命令块)的,因此, 我们必须要使用跳脱字符  来让他失去特殊意义才行 也适用其他特殊字符
#eg:grep -n 'go{2,5}g' regular_express.txt  ==g后2到5个o,再接一个g的字符串
#eg:grep -n 'go{2,}g' regular_express.txt   ==g后2个及以上的o,再接一个g的字符串

3.sed工具

[dmtsai@study ~]$ sed [-nefr] [动作]
选项与参数:
-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到屏幕上。但如果加上 -n 参数后,则只有经过 sed 特殊处理的那一行(或者动作)才会被列出来。
-e :直接在命令行界面上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个文件内, -f filename 则可以执行 filename 内的 sed 动作;
-r :sed 的动作支持的是延伸型正则表达式的语法。(默认是基础正则表达式语法)
-i :直接修改读取的文件内容,而不是由屏幕输出。
动作说明: [n1[,n2]]function
n1,n2 :不见得会存在,一般代表“选择进行动作的行数”,举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则“ 10,20[动作行为] ”
function 有下面这些咚咚:
a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c :取代, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正则表达式

* 以行为单位的新增/删除功能
#eg:
[root@localhost ddd]# nl /etc/passwd | sed '2,5d'    =='2,3d'删除2-3行;'2d':删除第二行;'3,$d':删除3到最后一行
     1	root:x:0:0:root:/root:/bin/bash
     6	sync:x:5:0:sync:/sbin:/bin/sync
#eg:
[root@localhost ddd]# nl /etc/passwd | sed '2a drink tea'   ==在第二行后加打印;如果是第二行之前用''2i drink tea'
     1	root:x:0:0:root:/root:/bin/bash
     2	bin:x:1:1:bin:/bin:/sbin/nologin
drink tea
     3	daemon:x:2:2:daemon:/sbin:/sbin/nologin
#eg:
[root@localhost ddd]# nl /etc/passwd | sed '2a line1nline2'  ==在第二行之后连续打印两行数据,可以用n或者+enter;如果想新增line1nline2 就加跳脱字符'2a line1\nline2'
     1	root:x:0:0:root:/root:/bin/bash
     2	bin:x:1:1:bin:/bin:/sbin/nologin
line1
line2

* 以行为单位的取代与显示功能
#eg:
[root@localhost ddd]# nl /etc/passwd | sed '2c No line2 number'    ==替代第二行数据
     1	root:x:0:0:root:/root:/bin/bash
No line2 number
#eg:
[root@localhost ddd]# nl /etc/passwd | sed -n '2,3p'  ==打印2-3行,也可以用head -n 3 /etc/passwd| tail -n 2;另使用-n
     2	bin:x:1:1:bin:/bin:/sbin/nologin
     3	daemon:x:2:2:daemon:/sbin:/sbin/nologin

* 部分数据的搜索并取代的功能
#sed 's/要被取代的字串/新的字串/g'
#eg:
#sed 's/^.*inet //g'  ==删除inet以及之前的打印
#sed 's/#.*$//g'      ==删除#及其注释的内容 #开始到行尾($)
#sed '/^$/d'          ==删除空白行,用/转义
#sed -i 's/.$/!/g'  ==把每一行行尾若为.则换成!在a动作增加的这种情况下 $表示最后一行。s替换的这种模式下,用的是正则。$表示行尾。
#sed -i '$a # This is a test'   ==最后一行加上打印;;首行必须有数据 才能插入;; 也可以echo "text" >> file

4.延伸正则表达式

#eg:去除空白行和首行为#的行列
	-1.grep -v '^$' regular_express.txt | grep -v '^#'				==管线命令
	-2.egrep -v '^$|^#' regular_express.txt						   ==延伸型的正则表达式;egrep也可以使用grep -E替代
  • 延伸型正则表达式的几个特殊符号

5.文件的格式化与相关处理

不需要重新以vim去编辑,通过数据流重导向配合下面介绍的printf功能,以及awk指令

5.1格式化打印:printf
[dmtsai@study ~]$ printf '打印格式' 实际内容
选项与参数:
关于格式方面的几个特殊样式:
a 警告声音输出
b 倒退键(backspace)
f 清除屏幕 (form feed)
n 输出新的一行
r 亦即 Enter 按键
t 水平的 [tab] 按键
v 垂直的 [tab] 按键
xNN NN 为两位数的数字,可以转换数字成为字符。
关于 C 程序语言内,常见的变量格式
%ns 那个 n 是数字, s 代表 string ,亦即多少个字符;
%ni 那个 n 是数字, i 代表 integer ,亦即多少整数码数;
%N.nf 那个 n 与 N 都是数字, f 代表 floating (浮点),如果有小数码数,
假设我共要十个位数,但小数点有两位,即为 %10.2f 啰!
  • eg:参考此链接
5.2 awk
#awk运行模式:awk '条件类型1{动作1} 条件类型2{动作2} ...' filename    print、printf,print会自动换行不用n
#awk处理流程:awk 的处理流程是:
	-1. 读入第一行,并将第一行的数据填入 $0, $1, $2.... 等变量当中;
	-2. 依据 "条件类型" 的限制,判断是否需要进行后面的 "动作";
	-3. 做完所有的动作与条件类型;
	-4. 若还有后续的“行”的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。
#awk变量名称:
	-1.NF:每一行($0)拥有的字段总数;$NF表示打印最后一个字段的值
	-2.NR:目前 awk 所处理的是“第几行”数据
	-3.FS:目前的分隔字符,默认是空白键
#awk逻辑运算符:
    >	大于          =	大于等于	  =2{total = $2 + $3 + $4 ; printf "%10s %10d %10d %10d %10.2fn", $1, $2, $3, $4, total}' 
      Name        1st        2nd        3th      Total
     VBird      23000      24000      25000   72000.00
    DMTsai      21000      20000      23000   64000.00
     Bird2      43000      42000      41000  126000.00
[root@localhost ddd]# cat pay.txt | awk '{if(NR==1) printf "%10s %10s %10s %10s %10sn",$1,$2,$3,$4,"Total"} ; NR>=2{total = $2 + $3 + $4 ; printf "%10s %10d %10d %10d %10.2fn", $1, $2, $3, $4, total}'   ==awk也支持if语句
      Name        1st        2nd        3th      Total
     VBird      23000      24000      25000   72000.00
    DMTsai      21000      20000      23000   64000.00
     Bird2      43000      42000      41000  126000.00

6.文件比对工具

1.diff:以行为单位比对,通常用在同一文件的(或软件)的新旧版本差异上,也可以用做目录的比对;可以把新旧的版本差异 制作为补丁文件,再由补丁文件更新旧文件即可;可以友echo $?输出
2.cmp:主要是以字节为单位比对
3.patch:版本的更新与还原 与diff一起使用

三、学习Shell Scripts

1.What is Shell Scripts

将一些 shell 的语法与指令(含外部指令)写在里面, 搭配正则表达式、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。

关于init(SystemV)和Systemd的介绍

关于换行符的介绍

1.关于编码:Dos和Windows采用回车+换行CR/LF表示下一行;而UNIX/Linux采用换行符LF表示下一行
2.scripts添加信息:功能、版本、作者信息、修改记录、需要的环境变量;最好使用vim
3.调试:bash -x [filename]
4.超出表达式递归:https://stackoverflow.com/questions/30404863/expression-recursion-level-exceeded
5.filename=$ {fileuser:-"filename"}  若变量fileuser为空 ,则返回"filename".若变量 fileuser 有值,则返回其当前值;以确保变量一直有值
6.善于使用$? || 以及&&进行判断前一个指令回传至对于后一个指令是否要进行的依据;也可以使用test指令
#根据日期创建文件
#!/usr/bin/sh
read -p  "please input filename: " fileuser
filename=${fileuser:-"filename"}   #检查fileuser是否存在
#获取日期
date1=$(date --date='1 days ago' +%Y%m%d) #一天前
date0=$(date  +%Y%m%d)   #今天
#配置文件名
file1=${filename}_${date1}
file0=${filename}_${date0}
#创建文件
touch "${file1}.log"
touch "${file0}.log"
#数值运算;可以用$((运算式))来定义运算式;
#!/usr/bin/sh
read -p "input first number: " first_num
read -p "input second number: " sec_num
total=$((first_num * sec_num))
echo -e "${first_num}*${sec_num}=${total}"
#另计算含有小数的数据时,可以用bc协助 比如echo "2.2+3.4"|bc

2.script的执行差异

  • 利用bash(sh)来下达脚本时,改script是在子程序的bash内执行的,会使用一个新的bash环境;所以是script内的变量在bash环境下无效

  • 利用source执行脚本,在父程序中执行,script中的变量会在bash中生效;source ~/.filename.sh

3.利用test指令的测试功能

主要进行数值、字符串和文件三个方面的检测

1.数值检测
#eg: test 1 -eq 2 && echo "yes" || echo "no"  
-eq:值 1 等于值 2
-ge : 值 1 大于或等于值 2
-gt : 值 1 大于值 2
-le : 值 1 小于或等于值 2
-lt : 值 1 小于值 2
-ne : 值 1 不等于值 2
2.比较文本
#eg: test "string1" = "string2" && echo "yes" || echo "no"   ==判断两个字符串是否相等
#eg: test -n "string1" && echo "yes" || echo "no"			==判断字符串长度是否大于0
==:字符串 1 匹配字符串 2;;等号两边要有空格!!!
!= : 字符串 1 与字符串 2 不匹配
-n:字符串长度大于0
-z:字符串长度等于 0
3.比较文件
-ef:文件具有相同的设备和 inode 编号(它们是同一个文件)
-nt : 第一个文件比第二个文件新
-ot:第一个文件比第二个文件旧
-d:文件存在并且是目录(directory)
-e : 文件存在
-f : 文件存在并且是文件(file)
-r:文件存在且可读
-s:文件存在且大小大于零
-w:文件存在且可写
-x:文件存在且可执行

`优化1:[ "$a" == "$b" ] 优化 [ x"$a" == x"$b" ]:这种办法避免了$b为空的情况下 bash报错
`优化2:[ x"$1" == x"1" ] 避免参数为空bash版本不兼容报错;但是也可以[ "$1" == ""]
4.多个条件判断
# -a表示and,-o表示or
#eg:test 4 -eq 4 -a "string1" == "string2" && echo "yes" || echo "no"		== -a条件同时满足
#eg: test 4 -eq 4 -o "string1" == "string2" && echo "yes" || echo "no"		 == -o条件之一满足
#检测文件是否存在
#!/usr/bin/sh
# Program:
# User input a filename, program will check the flowing:
# 1.) exist? 2.) file/directory? 3.) file permissions
# 1. 让使用者输入文件名,并且判断使用者是否真的有输入字串?
echo -e "Please input a filename, I will check the filename's type and permission. nn"
read -p "Input a filename : " filename
test -z ${filename} && echo "You MUST input a filename." && exit 0    #判断字符串长度是否为0 或用[ -z "${filename}"" ]判断
# 2. 判断文件是否存在?若不存在则显示讯息并结束脚本
test ! -e ${filename} && echo "The filename '${filename}' DO NOT exist" && exit 0
# 3. 开始判断文件类型与属性
test -f ${filename} && filetype="regulare file"
test -d ${filename} && filetype="directory"
test -r ${filename} && perm="readable"
test -w ${filename} && perm="${perm} writable"
test -x ${filename} && perm="${perm} executable"
# 4. 开始输出信息!
echo "The filename: ${filename} is a ${filetype}"
echo "And the permissions for you are : ${perm}"
5.利用判断符号[]
  • 必须要注意中括号的两端需要有空白字符来分隔
  • 中括号内字符需要使用双引号
#eg:[ -z "${HOME}" ]  ==判断$HOME是否为空  要双引号!
#eg:[ 4 -eq 4 ] && [ "string1" = "string2" ] && echo "yes" || echo "no"    

#!/usr/bin/sh
read -p "input (Y/N): " yn
[ "$yn" == "N" ] || [ "$yn" == "n" ] && echo "NO, interrupert" && exit 0   #或者用-o连接也可以,[ "${yn}" == "N" -o "${yn}" == "n" ] 
[ "$yn" == "Y" ] || [ "$yn" == "y" ] && echo "Yes, contine" && exit 0

4.Shell Scripts的默认变量 ($0,$1...)

/path/to/scriptname opt1 opt2 opt3 opt4
		$0 			$1	 $2	 $3   $4
$0代表脚本文件名,接着的第一个参数就是$1 
$# :代表后接的参数“个数”,以上表为例这里显示为4;
$@ :代表“ "$1" "$2" "$3" "$4" ”之意,每个变量是独立的(用双引号括起来);和$*不同 记忆$@即可
$* :代表“ "$1c$2c$3c$4" ”,其中 c 为分隔字符,默认为空白键, 所以本例中代表“ "$1 $2 $3 $4" ”之意。
# shift:造成参数变量号码偏移
#!/bin/bash
echo "the script name is $0"		#打印文件名
[ "$#" -lt 2 ] && echo "less than 2" && exit 0		#利用[]判断
echo "the whole($@) is $@"		#打印全部参数内容
echo "the 1st parameter($1) is $1"		#打印第一个参数

[root@localhost bin]# sh test.sh a b
the script name is test.sh
the whole($@) is a b
the 1st parameter($1) is a

5.条件判断式

5.1.利用if ....then
  • 单层、简单的条件判断式
if [ 条件判断式 ]; then
	当条件判断式成立时,可以进行的指令工作内容;
fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意! 
#eg: [ "${yn}" == "Y" -o "${yn}" == "y" ]  可替换为 [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]
#!/usr/bin/sh
read -p "input (Y/N): " yn
if [ "$yn" == "N" ] || [ "$yn" == "n" ] ; then
        echo "NO, interrupert" 
        exit 0			#执行完需退出 不然会执行最后一行打印
fi
if [ "$yn" == "Y" ] || [ "$yn" == "y" ] ; then
        echo "Yes, contine" 
        exit 0
fi
echo "Only y or n accepted" && exit 0
  • 多重、复杂条件判断式
# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况执行
if [ 条件判断式一 ]; then
当条件判断式一成立时,可以进行的指令工作内容;
elif [ 条件判断式二 ]; then
当条件判断式二成立时,可以进行的指令工作内容;
else
当条件判断式一与二均不成立时,可以进行的指令工作内容;
fi
#检测键盘输入
#!/usr/bin/sh
read -p "input (Y/N): " yn
if [ "$yn" == "N" ] || [ "$yn" == "n" ] ;then
        echo "NO, interrupert" && exit 0
elif [ "$yn" == "Y" ] || [ "$yn" == "y" ] ;then
        echo "Yes, contine" && exit 0
else
        echo "Only y or n accepted" && exit 0
fi
#检测进程
#!/usr/bin/sh
process_chk_file=/home/ddd/process_chk.txt
netstat -antp > ${process_chk_file}
process_port=$(grep ":22" ${process_chk_file})		#可使用$(...)进行引用;等号两边不能有空格;简单赋值的时候不需要$(...)
if [ "${process_port}" = "" ] ; then		#空字符""
        echo "Error,process SSH not runnning"
else
        echo "Log,process SSH is running"
fi
5.2.利用case...in...esac判断
case $变量名称 in
模式1)
    command1
    command2
    ;;		#每个类别结尾使用两个连续的分号来处理
模式2)
    command1
    command2
    ;;
*)		#最后一个变量内容都会用 * 来代表所有其他值
    command1
    command2
    ;;
esac
#!/usr/bin/sh
read  -p "input a num:" aNum
case $aNum in		
    1)  echo 'You select 1'
    ;;		
    2)  echo 'You select 2'
    ;;
    *)  echo 'You do not select a number between 1 to 4'
    ;;
esac
5.3.利用function功能
#!/usr/bin/sh
function printit(){
        echo -n "ur choice is "
}
case ${1} in
    "one")
    printit; echo ${1} | tr 'a-z' 'A-Z'		#调用;转换大小写
    ;;
    *)  echo 'over'
    ;;
esac

6.循环loop

6.1 while do done, until do done (不定循环)
while [ "${yn}" != "yes" -a "${yn}" != "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done

until [ "${yn}" == "yes" -o "${yn}" == "YES" ]
do
read -p "Please input yes/YES to stop this program: " yn
done

s=0 # 这是加总的数值变量
i=0 # 这是累计的数值,亦即是 1, 2, 3....
while [ "${i}" != "100" ]
do
i=$(($i+1)) # 每次 i 都会增加 1
s=$(($s+$i)) # 每次都会加总一次!
done
6.2 for...in...do...done (固定循环)
for var in con1 con2 con3 ...
do
程序段
done

for animal in dog cat elephant
do
echo "There are ${animal}s.... "
done

#检测服务器状态
#usr/bin/sh
network="192.168.15"
ping_chk_file=/home/ddd/ping_chk_file_$(date +%Y%m%d).txt
[ ! -e "$ping_chk_file" ] && touch ${ping_chk_file}		#检测文件 不存在则创建
#cat /dev/null > ${ping_chk_file}			#文件置空
[ ! -s "$ping_chk_file" ] && echo "# ping-check" >> ${ping_chk_file}		#文件为空则添加首行 可以为下文的sed -i服务;
echo "excuting"
for sitenu in $(seq 120 130)		#seq 连续
do
        ping -c 1 -w 1 ${network}.${sitenu} >/dev/null && result=0 || result=1  #免除界面打印
        if [ "$result" = 0 ] ; then
                echo "$(date "+%Y-%m-%d %H:%M:%S"): server ${network}.${sitenu} is UP" >> ${ping_chk_file}	#方便简单
        #       sed -i '$a server ${network}.${sitenu} is UP' ${ping_chk_file}		#高级,但需要首行有数据才能处理
        else
                echo "$(date "+%Y-%m-%d %H:%M:%S"): server ${network}.${sitenu} is DOWN" >> ${ping_chk_file}
        #       sed -i '$a server ${network}.${sitenu} is DOWN' ${ping_chk_file}
        fi
done

#检测文件权限
#usr/bin/sh
read -p "Please input a directory: " dir
if [ "${dir}" == "" -o ! -d "${dir}" ] ; then   #经常用吧
echo "The ${dir} is NOT exist in your system."
exit 1
fi
# 2. 开始测试文件啰~
filelist=$(ls ${dir}) 		# 列出所有在该目录下的文件名称;注意格式 引用赋值
for filename in ${filelist}
do
perm=""
test -r "${dir}/${filename}" && perm="${perm} readable"
test -w "${dir}/${filename}" && perm="${perm} writable"
test -x "${dir}/${filename}" && perm="${perm} executable"
echo "The file ${dir}/${filename}'s permission is ${perm} "
done
6.5 for...do...done 的数值处理
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
这种语法适合于数值方式的运算当中,在 for 后面的括号内的三串内容意义为:
初始值:某个变量在循环当中的起始值,直接以类似 i=1 设置好;
限制值:当变量的值在这个限制值的范围内,就继续进行循环。例如 i

7.shell script的追踪与debug

sh [-nvx] scripts.sh
选项与参数:
-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!

四、补充

1.打印进度条

#!/bin/sh
b=''
for ((i=0;$i

2.文件描述符(参考第一章18小节)

用途

/dev/null 是一个特殊的设备文件,它丢弃一切写入其中的数据 可以将它 视为一个黑洞, 它等效于只写文件, 写入其中的所有内容都会消失, 尝试从中读取或输出不会有任何结果,同样,/dev/null 在命令行和脚本中都非常有用/dev/null通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成,任何你想丢弃的数据都可以写入其中

丢弃标准输出、丢弃标准错误输出

在写shell脚本的时候,只想通过命令的结果执行后面的逻辑,而不想命令执行过程中有一大堆中间结果输出,这时候可以把命令执行过程中的输入全部写入 /dev/null

#丢弃标准输出
#!/bin/bash
command -v $1 >/dev/null 		#command -v 命令名 是查找指定命令名的命令是否存在,如果存在,输出指定命令名的路径,否则,不做任何输出;执行./a.sh top  则不打印路径
if [[ $? -eq 0 ]]; then
	echo "command $1 exist..."
else
	echo "command $1 not exist..."
fi

#丢弃标准错误输出
#!/bin/bash
rm $1 >/dev/null 2>$1		#或用2>/dev/null替代 丢弃标准错误输出

清空文件内容

cat /dev/null > t.txt

3.进程检测

#!/bin/bash
# 如果此机器不存在这个,则配置为1
aboss5_flag=0
aboss2_flag=1
tomcat_flag=0
mycat_flag=0
# procmgr start
procmgr_ids=`ps -ef | grep procmgr | grep -v "grep" | awk '{print $2}'`
for id in $procmgr_ids
do
        pathDir=`ls -al /proc/$id/cwd | awk '{print $NF}'`	#取出id	
        echo [$id]:[$pathDir]
        if [[ "$pathDir" == *"aboss5"* ]]; then		#两层[]为匹配正则*
                aboss5_flag=1
                echo "[NOTE] aboss5 procmgr is already started."
        elif [[ "$pathDir" == *"aboss2"* ]]; then
                aboss2_flag=1
                echo "[NOTE] aboss2 procmgr is already started."
        fi
done

4.关于双方括号

双方括号的用法说明

其他括号的用法说明

  • 支持字符匹配
#!/usr/bin/sh
#匹配结果和不带""没差
if [[ $1 == "s"* ]]; then
        echo "s*"
elif [[ $1 == *"s" ]]; then
        echo "*s"
elif [[ $1 == *"s"* ]] ;then
        echo "*s*"
else
        echo "none"
fi

if [[ $1 == *"s"* ]];	#带双引号 双* 进行元字符匹配;和下例没差
if [[ $1 == s* ]];		#不带双引号,匹配s*的字符串
if [[ $1 =~ sa* ]];		#=~进行正则匹配 匹配s/sa...等
  • 支持&& -a -o多个条件连接处理

    if [[ "a" == "a" && 2 -gt1 ]]
    

5.注释

1. #单行注释
2. :`多行注释`
3. 

6.引号

对于打印文本 单引号和双引号没有区别;打印输出一个已定义的变量,则需要使用双引号

#!/usr/bin/sh
read -sp  "num:" num		#-s支持静默不在界面打印
echo -e "\n $num"		#-e支持转义字符

7.关于日期格式化

[root@localhost scripts]# date +%Y-%m-%d" "%H:%M:%S
2022-05-06 00:14:42
+%Y	年 2022
  m	月 01
  d	日 01
  H 时 二十四小时制
  M	分 
  S	秒

8.sleep

sleep 1d 2h 3m 30s  默认是秒  也可用作定时执行 不规范

五、案例

https://blog.csdn.net/u010230971/article/details/80335522

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认