Hefery 的个人网站

Hefery's Personal Website

Contact:hefery@126.com
  menu
73 文章
0 浏览
0 当前访客
ღゝ◡╹)ノ❤️

Shell Script

Vim

Vim模式

一般命令模式:输入"i,o,a"进入编辑模式;输入": / ?"进入命令行模式

编辑模式:ESC进入一般命令模式

命令行模式:ESC进入一般命令模式

Vim操作

补齐

# 文件内容文字
Ctrl + N
# 文件名
Ctrl + F
# 拓展名
Ctrl + O

移动

文首:gg   文尾:G、Shift+g
行首:0    行尾:$、Shift+4
下一页:Ctrl + F
上一页:Ctrl + B
指定行:行号+Shift+g
下移行:行号+Enter

删除

光标位置:行号+x
光标前:d+0
光标后:D
光标所在行:dd  删光标以下5行:5+dd
单词:单词首字符:d+w 删除整个单词
单词中字符:d+w 删除单词后面

复制/粘贴/撤销

#复制:n为行号
nyy
yw  # 单词
#剪切
dd
#粘贴
p/P
#撤回
u

可视

# 切换可视模式
v
# 复制y  删除d

查找

/查找内容   #光标向下查找,到最下返头
?查找内容  #光标向上查找,到最上返尾

替换

# ESC切换末行模式
# 光标移动至要修改行
:s/要替换的字符串/填充字符         #第一个替换
:s/要替换的字符串/填充字符/g       #整行替换
:@s/要替换的字符串/填充字符/g      #全文替换
:27,30s/要替换的字符串/填充字符/g  #指定行替换

保存

#ESC切换末行模式
!q   #退出
!w   #保存
!wq  #保存退出

分屏

#ESC切换末行模式
#水平
	进入  :sp  
	切换  Ctrl+ww
	保存  :wqall  :q   :wall  :qall
#垂直
	进入  :vsp hello.c
	切换  Ctrl+ww
	保存  :wqall

Shell

Shell简介

# 查看当前环境使用的默认解析器
echo $SHELL  	# /bin/bash

# 命令查找顺序
1.以相对/绝对路径执行
2.以alias查找执行
3.以bash内置命令执行
4.以$PATH变量顺序查找执行

# 查询命令是否为Shell内置命令
type [-tpa] name

编写习惯

脚本头部信息应当包含:

  • 脚本功能
  • 版本信息
  • 作者及联络
  • 脚本历史
  • 声明环境变量
#!/bin/bash
#-----------------------------------------------------#
#  Program:
#       User input his/her first name and last name
#       Program shows his/her full name
#  OS Version: CentOS 7.x
#  Author: Hefery    Email: hefery@126.com
#  History:
#       2020/08/06 21:37 -- Hefery --  First release
#-----------------------------------------------------#
PATH=/bin:/sbin:/user/bin:/user/sbin:/user/local/bin:/user/local/sbin:~/bin

第一行 #!/bin/bash 声明脚本使用的shell名称 #!加载bash相关配置文件

脚本变量

变量的使用

# 查看系统环境变量
env
HOSTNAME # 主机名
SHELL 	 # 使用的Shell
USER 	 # 使用者
PATH 	 # 环境变量
LANG  	 # 语系
HOME	 # 根目录

# 定义并设置
val_name=Hefery

# 删除变量
unset mval_nameyname

# 定义环境变量
echo ${val_name}

# 设置常量
readonly val_name

变量设置规则:

  • “=” 两边不能直接有 space
  • 变量名只能以字母开头,可使用数字
  • 变量内有 space 可以用双引号[""]、单引号['']
  • 可用转义符[/]表示特殊字符

环境变量

自定义系统环境变量:

  • 初始化Shell环境时会加载全局配置文件/etc/profile
  • 编辑/etc/profile文件 -> source /etc/profile

Shell登录环境

  • 判断:echo $0
    -bash:Shell登录环境
    bash:Shell非登录环境
  • 切换:
    su 用户名 -l # 切换到指定用户,加载Shell登录环境
    su 用户名 # 切换到指定用户,加载非Shell登录环境

环境变量加载流程:

  1. Shell登录环境 -> 执行/etc/profile加载系统环境变量 -> 执行/etc/profile.d/*.sh加载系统环境变量 ->
    执行用户/.bash_profile加载用户环境变量 -> 加载用户/.bashrc加载用户环境变量 -> 执行/etc/basgrc加载系统环境变量
  2. 非Shell登录环境 -> 加载用户/.bashrc加载用户环境变量 -> 执行/etc/basgrc加载系统环境变量 ->
    执行/etc/profile.d/*.sh加载系统环境变量

特殊变量

$n:执行脚本传入参数
    script.sh   opt1 opt2 opt3 opt4 ...
    脚本文件名$0   $1   $2   $3   $4
$#:获取输入参数个数  4
$@:获取以后所有输入参数  "$1" "$2" "$3" "$4"
$*:获取当前所有输入参数  "$1c$2c$3c$4", c为分隔符,默认为空格
$?:获取上一个Shell命令的退出状态码或函数返回值
$$:获取当前Shell环境的进程ID

字符串

截取:
    ${val_name:start:length}
    ${val_name:start}
    ${val_name:0-start:length}
    ${val_name:0-start}
    ${val_name#*chars}
    ${val_name##*chars}
    ${val_name%chars*}
    ${val_name%%chars*}

数组Array

Bash Shell只支持一维数组

数组定义:
	array_name=(item1 item2 ...)
	array_name([index1]=item1 [index2]=item2 ...)

数组属性:
	单个数组元素:${array_name[index]]
	所有数组元素:${array_name[@ | *]}
	获取数组长度:${#array_name[@ | *]}

数组拼接:
	array_name=(${array1[@]} ${array1[#]})

数组删除:
	删除单个元素:unset array_name[index]
	删除整个数组:unset array_name

特殊符号

符号意义
*任意多个字符
任意一个字符
[ - ]有减号:编码顺序内的所有字符 [0-9]
[^ ]中括号第一个字符为“^”,反向选择 [^abc]:一定有一个字符是非a、b、c的其它字符
符号意义
#注释符
\*转义符:将特殊字符或通配符转换为一般字符
;连续命令执行分隔符
~用户家目录
$使用变量前导符
&任务管理:将命令变成后台命令
!逻辑运算:非
/路径分隔符
>,>>数据重定向:输出定向 分别是替换、累加
<,<<数据重定向:输入定向
‘ ’单引号,不具有变量替换功能
“ ”双引号,具有变量替换功能
中间是可先执行的命令,相当于 $( )
( )中间为子shell的起始和结束
{ }中间为命令快
RE字符意义
^word待查找的word在行首
word$待查找的word在行尾
.一定存在的一个任意字符
\转义
*任意多个字符
[list]*list:想要取的字符 [aliy]
[n1-n2]想要选取的字符范围 [0-9]、[a-z]、[A-Z]
[^list]不要出现的字符/范围
{n,m}连续n-m个字符
+*重复前RE字符/字符串 ‘go+d’:god、good、goood
前一个RE字符
|逻辑或 ‘gd| good | dog ’
( )群组字符串 ‘g(la
( ) +*多个重复群组 ‘A(xyz)+C’:A开头,C结尾,中间有一个以上xyz字符串

运算符

算数运算符

expr:求值表达式	result=`expr 算数表达式`
运算符:+ - * / % =(赋值)

比较运算符

整数比较

数学计算:((表达式))
整数运算:$[表达式]
运算符说明样例
-eq、==等于[$a -eq $b]
-ne、!=不等于[$a -ne $b]
-gt、>大于[$a -gt $b]
-lt、<小于[$a -lt $b]
-ge、>=大于等于[$a -ge $b]
-le、<=小于等于[$a -le $b]

字符串比较

字符串比较:[[]]、[]
	1.字符分隔比较:[[]]不会
	2.是否支持转义:[[]]不用转义,[]手动转义
运算符说明样例
==、=等于
!=不等于
<小于[$a<$b ]
>大于
-z检查字符串长度是否为0,为0返回true[ -z $a ]
-n检查字符串长度是否不为0,不为0返回true[ -n $a ]

逻辑运算符

布尔

布尔运算符说明样例
!取反
-oor或
-aand与

逻辑

逻辑运算符说明样例
&&逻辑AND[[ 表达式1 && 表达式2 ]]
||逻辑OR[[ 表达式1|| 表达式2 ]]
[[ !表达式 ]]

文件运算符

运算符说明样例
-b file检测文件是否为块设备文件,是返回true[[ -b &file ]]
-c file检测文件是否为字符设备文件,是返回true[[ -c &file ]]
-d file检测文件是否为目录,是返回true[[ -d &file ]]
-f file检测文件是否为普通文件(非设备文件和目录),是返回true[[ -f &file ]]
-g file检测文件是否设置了SGID位,是返回true[[ -g &file ]]
-k file检测文件是否设置了粘着位(Stick Bit),是返回true[[ -k &file ]]
-p file检测文件是否为管道文件,是返回true[[ -p &file ]]
-u file检测文件是否设置了SUID位,是返回true[[ -u &file ]]
-r file检测文件是否可读,是返回true[[ -r &file ]]
-w file检测文件是否可写,是返回true[[ -w &file ]]
-x file检测文件是否可执行,是返回true[[ -x &file ]]
-s file检测文件是否为空(文件大小为0),不为空返回true[[ -s &file ]]
-e file检测文件或目录是否存在,存在返回true[[ -e &file ]]
file1 -nt file2new than,file1是否比file2新[[ file1 & file2 ]]
file1 -ot file2old than,file1是否比file2旧[[ file1 & file2 ]]

逻辑语句

命令替换:赋值等号和替换字符间没有空格

  • 反引号(``):test=`date`
  • $():test=$(date)

条件

判断:[ "${变量}" == "XXX" ]  # 注意空格
	read -p "Please input (Y/N):" yn
	[ "${yn}" == "Y" -o "${yn}" == "y" ] && echo "OK" && exit 0
	[ "${yn}" == "N" -o "${yn}" == "n" ] && echo "OH" && exit 0

条件:
	# 1.if...then...fi
	# 简单判断:if [ 条件判断式 ]; then  ...  fi
	if [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]
	then
		echo "OK, continue"
		exit 0
	fi

	# 复杂判断:if [ 条件判断式 ]; then  ... elif ...  else ...  fi
	if [ "${yn}" == "Y" ] || [ "${yn}" == "y" ]
	then
		echo "OK, continue"
	elif [ "${yn}" == "N" ] || [ "${yn}" == "n" ]
	then
		echo "OH, interrupt"
	else
		echo "I don't know"
	fi

	# 2.case...esac
	case ${1} in
		"one")
			echo "The one"
			;;
		"two")
			echo "The two"
			;;
		*)
			echo "Others"
			;;
	esac

循环

# 1.while/until...do...done
# 满足 condition 进入循环,否则跳过循环
while [ condition ] 
do
	...
	continue # 结束当前循环,接入下一次循环
	break	 # 结束当前循环
done

s=0
i=0
while [ "${i}" != "100" ]
do
	i=$(($i+1))
	s=$(($s+$i))
done


# 满足 condition 终止循环,否则继续循环
until [ condition ] 
do
	...
done


# 2.for...do...done
# 字符处理
for var in [col1 col2 col3... | {start..end}]
do
	...
done

for (( i=start; i<=end; i=i++ ))
do
	...
done


users=$(cut -d ":" -f1 /etc/passwd)
for username in ${users}
do
	id ${username}
done

# 数值处理
for (( 初始值; 限制值; 赋值运算 ))
do
	...
done

s=0
for (( i=1; i<=${nu}; i=i+1 ))
do
	s=$((${s}+${i}))
done

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

函数

Shell脚本与函数的区别:
	Shell程序/命令会在子Shell中运行,会开启独立的进程运行;Shell函数在当前的Shell中运行
	通过自定义函数实现代码复用

# shell脚本由上而下、由左而右执行,函数一定要设置在程序前面
function funname() {
	...
	[return]
}

# 调用函数
funname 参数1 参数2
函数参数说明
$#传递到脚本或函数的参数个数
$*、$@以一个单字符串显示所有传入参数
$$脚本运行的当前进程ID
$!后台运行的最后一个进程ID
$?显示最后命令的退出状态

数据重定向

将某个命令执行后应该出现在屏幕上的数据传输到其它地方
    1.标准输入    stdin:代码为0  使用 < 或 <<		Shell程序默认会从stdin文件最后读取输入数据
    2.标准输出   stdout:代码为1  使用 > 或 >>		Shell程序默认会向stdout文件输出正确数据
    3.标准错误输出stderr:代码为2  使用 2> 或 2>>   Shell程序默认会向stderr文件输出错误信息

<  :覆盖,若文件不存在则自动创建
<< :追加,若文件不存在则自动创建

# 将 ll 命令的输出覆盖掉根目录下的 rootfile 文件中
ll / > ~/rootfile
# 将 ll 命令的输出追加到根目录下的 rootfile 文件中
ll / > ~/rootfile

# 将正确信息和错误信息分开定向
ll / > ~/log_right 2> log_error
# 丢弃错误信息,正确信息输出到屏幕
ll / > ~/rootfile 2> /dev/null
# 正确、错误信息全部存到一个 list 文件
ll / > ~/rootfile > list 2> list # 错:两股数据可能会交叉写入,造成次数错乱
ll / > ~/rootfile > list 2>&1	 # 对
ll / > ~/rootfile &> list		 # 对

脚本执行

脚本调试方式
	sh [-nvx] scripts.sh
	-n:不执行,仅查询语法问题
	-v:执行脚本前,先将脚本文件内容输出屏幕
	-x:将脚本文件内容输出屏幕
	# sh -x scripts.sh

脚本执行方式
	1. source script:在父进程中执行
	2. sh script:
	3. ./script:先赋权限

内置命令

内置命令
alias起别名alias 别名=“命令”
unalias删除别名unalias 别名;unalias -a
read读取控制台输入
bind显示当前关键字与函数的绑定情况,或将关键字与readline函数或宏进行绑定
break从最内层循环跳出
cd改变目录
declare显示所有变量,或用可选属性声明变量
echo输出显示
exec运行命令
exit退出Shell
export声明变量
help显示关于内置命令的有用信息
history显示带行号的命令历史列表
kill向由PID号或作业号指定的进程发送信号
let用来计算算术表达式的值,并把算术运算的结果赋给变量
local用在函数中,把变量的作用域限制在函数内部
logout退出登录Shell
pwd当前的工作目录
readonly将变量var设为只读,不允许重置该变量
return从函数中退出
set设置选项和位置参量
shift将位置参量左移n次
stop pid暂停第pid号进程的运行
suspend终止当前Shell的运行
test检查文件类型,并计算条件表达式
times显示由当前Shell启动的进程运行所累计用户时间和系统时间
type显示命令的类型
typeset同declare。设置变量并赋予其属性
ulimit显示或设置进程可用资源的最大限额
umask用户文件关于属主、属组和其他用户的创建模式掩码
unset取消指定变量的值或函数的定义
wait等待pid号为n的后台进程结束,并报告它的结束状态
exit:退出,并返回一个状态码
	应用:
		结束当前Shell进程
	状态码:
		0:命令执行成功
		非0:命令执行失败

expr:
	计算字符串长度:expr length 字符串
	截取字符串:expr substr 字符串 start end
	获取在字符串出现位置:expr index 字符串 substr

select:
	菜单选择输入,无限循环,Ctrl + D结束循环

select val in menu1 menu2...
do
	...
done

test:整数、字符串、文件对比
	整数:
        if test num1 options num2	# options:-eq -ne -gt -ge -lt -le
        then
            ...
        fi
    字符串:
    	=、==:对于返回0表示成功
    	!=:不等于
    	<:小于
    	>:大于
    	-z 字符串:字符串长度为0为true
    	-n 字符串:字符串长度不为0为true
	文件:
		-e 文件名:exist,文件存在为true
		-r 文件名:read,文件存在且可读为true
		-w 文件名:write,文件存在且可写为true
		-x 文件名:execute,文件存在且可执行为true
		-s 文件名:string,文件存在且至少有一个字符为true
		-d 文件名:directory,文件存在且为目录为true
		-f 文件名:file,文件存在且为普通文件为true
		-d 文件名:文件存在且可块文件为true

declare:设置变量属性 declare [+/-][aArif][val_name=val_value]
	+:设置属性
	-:取消属性
	a array:设置为普通索引
	A Array:设置为key-value关联数组
	r readonly:设置变量为只读
	x export:设置变量为环境变量
	i int:设置变量为整型
	f function:设置为函数变量

read:读取控制台输入
	参数:
		-a array:读取的数据赋值给数组,index从0开始
		-d delimiter:用字符串delimiter读取指定结束的位置
		-n num:读取num个字符
		-p prompt:显示信息,提示内容为prompt
		-r:原样读取,不会转义
		-s:静默模式,不会在控制台输出输入内容
		-t seconds:设置超时时间
		-u fd:使用文件描述符fd作为输入源

	提示信息:read -p "请输入姓名,年龄,爱好:" name age hobby
	读取单个字符:read -n 1 -p "是否要删除数据(y/n)" char
	核对密码:
		read -t 20 -sp "请输入密码(20S)" pwd1
		read -t 20 -sp "请再次输入密码(20S)" pwd2
		if [ ${pwd1} == ${pwd2} ]
		then
			echo "密码正确"
		else
			echo "密码错误"
		fi

文本处理

grep查找

属性选项:
     -r :递归搜索
   -i :忽略大小写(ignore case)
   -v :反过来(invert),只打印没有匹配的,而匹配的反而不打印
   -n :显示行号
   -w :被匹配的文本只能是单词,而不能是单词某一部分,如文本中有liker,而我搜寻的只是like,就可以使用-w选项来避免匹配liker
   -c :显示总共有多少行被匹配到了,而不是显示被匹配到的内容,注意如果同时使用-cv选项是显示有多少行没有被匹配到
   -o :只显示被模式匹配到的字符串
   -color :将匹配到的内容以颜色高亮显示
   -E :开启扩展(Extend)的正则表达式
   -A  n:显示匹配到的字符串所在的行及其后n行,after
   -B  n:显示匹配到的字符串所在的行及其前n行,before
   -C  n:显示匹配到的字符串所在的行及其前后各n行,context

find查找

查找文件:
	当前工作目录:find . -name file_name
	指定路径查找:
		find /hefery/devhb -name file_name
		find /hefery/devhb -type f -name file_name
	忽略大小写查:find /hefery/devhb -iname file_name
	根据权限查找:
		find /hefery/devhb -type f -perm 0777 -print	# 权限为777
		find /hefery/devhb -type f ! -perm 777			# 没有 777 权限
		find / -type f -perm 0777 -print -exec chmod 644 {} \    # 权限为 777 且 chmod 为 644 的文件
	查找只读文件:find /hefery/devhb -perm /u=r
	查找可执行文件:find /hefery/devhb -perm /a=x
	查找和删除多个文件:find . -type f -name "*.txt" -exec rm -f {} \
	查找所有空文件:find /tmp -type f -empty
	查找最近 50 天修改过的文件:find / -mtime 50
	查找最近 50 天访问过的文件:find / -atime 50
	查找最近 50-100 天修改过的文件:find / -mtime +50 –mtime -100
	查找过去 1 小时内更改过的文件:find / -cmin -60
	查找过去 1 小时内访问过的文件:find / -amin -60
	找到 50MB 的文件:find / -size 50M
	查找 50MB – 100MB 之间的大小:find / -size +50M -size -100M
	查找和删除 100MB 文件:find / -type f -size +100M -exec rm -f {} \
	查找特定文件并删除:find / -type f -name *.txt -size +10M -exec rm {} \

查找目录:
	find /hefery/devhb -type d -name dir_name
	find / -type d -perm 777 -print -exec chmod 755 {} \   # 查找权限为 777 且 chmod 为 755 的目录
	find /tmp -type d -empty# 查找所有空目录


wc统计

文本统计:
	单词个数:wc -w < hello.txt
	单词行数:wc -l < hello.txt
	单词字节数:wc -c < hello.txt

cut列处理

提取Bash进程的PID:
	ps -aux | grep bash

提取IP地址:
	ifconfig | grep broadcast | cut -d " " -f 10
参数选项说明
-f 提取范围以列号为单位进行切割
-c 提取范围以字符为单位进行切割
-b 提取范围以字节为单位进行切割
-d 自定义分隔符默认为制表符
提取范围说明
n-第n[列]
n-m第n到第m[列 字符 字节]中间的数据
-m第m[列]
n1,n2…指定枚举值获取列

sed编辑

文本流处理器:对文本文件的每一行数据匹配后进行CRUD
sed 参数选项 [模式匹配 | sed程序命令] 文件名

添加数据:
	sed "3ahefery" sed.txt   # 在第三行后添加hefery,没有修改源文件
	sed "/devhb/ahefery" sed.txt   # 在内容devhb后添加hefery
	sed "/devhb/ihefery" sed.txt   # 在内容devhb前添加hefery

删除数据:
	sed "2d" sed.txt     # 删除第二行数据
	sed "1~2d" sed.txt   # 删除奇数行数据:第一行开始,每隔2行删除一行
	sed "1,3d" sed.txt   # 删除第一行到第三行的数据
	sed "$d" sed.txt     # 删除最后一行数据
	sed "/hefery/d" sed.txt   # 删除匹配hefery的行数据
	sed "/hefery/,d" sed.txt   # 删除匹配hefery的行到最后一行的数据
	sed "/hefery/,+1d" sed.txt   # 删除匹配hefery的行到下一行的数据
	sed "/hefery\|hefery/!d" sed.txt   # 删除匹配hefery的行到最后一行的数据

修改数据:
	sed "1chefery" sed.txt   # 将文件的第一行修改为hefery
	sed "$chefery" sed.txt   # 将文件中的最后一行修改为hefery
	sed "/hefery/chello" sed.txt   # 将文件中的hefery修改为hello
	sed -n "s/hefery/hello/2pw sed2.txt" sed.txt   # 将第2个匹配的hefery替换为hello,后的内容写入文件
	sed -n "s/hefery/hello/2p" sed.txt > sed2.txt  # 将第2个匹配的hefery替换为hello,后的内容写入文件
	sed "s/$/& test" sed.txt   # 将每行的末尾拼接hefery
	sed "s/^/#/' test" sed.txt # 将每行的行首添加注释#

查询数据:
	sed -n '/hefery/p' sed.txt   # 查询含有hefery的行
	第一行删除,并将hefery替换为hello:
		sed -e '1d' -e 's/hefery/hello/g' sed.txt
		sed '1d;s/hefery/hello/g' sed.txt
参数选项说明
-e直接在指定列模式上进行sed动作编辑
-i对内容进行修改
-f后跟保存了sed指令的文件
-n取消默认输出,只显示处理过的行
-r使用拓展正则表达式
sed程序命令说明
a新增add
c修改change
d删除delete
i插入insert
p打印print
s替换substitute
=打印被匹配行的行号
n读取下一行.

awk分析

文本分析工具:
awk 'pattern{action}' {filename}
参数选项说明
-F指定输入文件拆分分隔符
-V赋值一个用户定义变量
内置变量说明
ARGC命令行参数个数
ARGV命令行参数排列
ENVIRON支持队列中系统环境变量的使用
FILENMAEawk浏览的文件名
FNR浏览文件的记录数
FS设置输入域分隔符
NF浏览记录的域的个数,根据分隔符分隔后的列数
NR已读的记录数
OFS输出域分隔符
ORS输出记录分隔符
RS控制记录分隔符
$n**$0:整条记录 **$**1:当前行的第一个域 **$2:当前行的第二个域
$NF最后一列的信息

sort排序

参数选项说明样例
-n依照数值大小排序
-r以相反的顺序排序
-t设置排序时设置的分隔符
-k指定需要排序的列
-d排序时,除英文、数字和空格字符外概不处理
-f排序时,将小写视为大写
-b忽略每行前面开始的空格
-o排序的结果输出到文件
-u输出结果去重处理
-m合并排序好的文件

标题:Shell Script
作者:Hefery
地址:http://hefery.icu/articles/2021/12/06/1638767132634.html