1、获取脚本当前所在路径

cd "$(dirname -- "$0")" && pwd

2、数组接收多个值

port_list_str=$1
port_list=(${port_list_str//,/ })
for index in ${!port_list[@]}
do
var=${port_list[$index]}
echo $var
done

演示

[root@VM-16-16-centos ansible]# sh ss.sh  11,22,33
11
22
33

3、比较浮点值

a=1.1
b=2.3
if [ `echo "$a < $b" | bc` -ne 0 ];then
echo "$a < $b"
fi

演示

[root@VM-16-16-centos ansible]# sh ss.sh 
1.1 < 2.3

4、删除匹配文本所在的行

sed -i -e '/文本/d'

演示

echo "111122" >> /etc/hosts
echo "333322" >> /etc/hosts


//删除匹配到的行
sed -i -e '/1111/d' /etc/hosts

返回

[root@VM-16-16-centos ansible]# cat /etc/hosts
127.0.0.1 VM-16-16-centos VM-16-16-centos
127.0.0.1 localhost.localdomain localhost
127.0.0.1 localhost4.localdomain4 localhost4

::1 VM-16-16-centos VM-16-16-centos
::1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6


333322

5、替换文件中最后一行的数据

sed -i '$s/.*/要替换的文本/'  //$表示文件最后一行,$紧跟s命令替换最后一行

演示

//创建测试文本
cat > /tmp/test.log <<EOF
111
222
333
EOF

//查看
[root@VM-16-16-centos ansible]# cat /tmp/test.log
111
222
333


//修改
sed -i '$s/.*/xxx/' /tmp/test.log

shell脚本常用语句记录--持续更新_运维

6、删除文本最后一行的数据

sed -i '$d' 文件

 7、ss.sh: line 7: [: ==: unary operator expected

我们可能使用了如下的语法,当变量STATUS没有值的时候就会报错

if [ $STATUS == "OK" ];then  

echo "OK"

fi

shell脚本常用语句记录--持续更新_服务器_02

这里只要将中括号换成双中括号 改为等于值即可

if [[ $STATUS = "OK" ]];then   //双中括号, == 改成 =
echo "OK"
fi

 

shell脚本常用语句记录--持续更新_sed_03

8、按照日期备份文件

NOW=$(date +"%m-%d-%Y") 
FILE="backup.$NOW.tar.gz"
tar -zcvf /tmp/$FILE /tmp

9、输出文本中倒数第二列的值

awk '{print $(NF-1)}'

演示

cat > /tmp/test.log <<EOF
123 345 567 789 //567是倒数第二列的值
EOF


//查看
[root@VM-16-16-centos tmp]# cat /tmp/test.log | awk '{print $(NF-1)}'
567

10、判断变量、文件、目录是否有值

if [ -n "变量" ]; then  //判断变量是否有值

-f 判断是否有文件
-d 判断是否有目录

11、获取匹配到数据的 值的上一行或下一行

cat > /tmp/test.log  <<EOF
AAAAAAA
BBBBBBB
CCCCCCC
DDDDDDD
EEEEEEE
EOF


//查看匹配到值的上一行 和本身
[root@VM-16-16-centos tmp]# cat /tmp/test.log | grep -B 1 "BBB"
AAAAAAA
BBBBBBB



//查看匹配到值的下一行 和本身
[root@VM-16-16-centos tmp]# cat /tmp/test.log | grep -A 1 "BBB"
BBBBBBB
CCCCCCC

12、给文件中所有行首行尾添加数据

//给文件所有行尾添加数据
sed -i 's/$/ xxx/' /tmp/test.log


//给文件所有行首添加数据
sed -i 's/^/ xxx/' /tmp/test.log

13、给指定匹配到的文本后、匹配的文本的末尾追加配置

sed 's/AAAAAAA/&123/' /tmp/test.log

shell脚本常用语句记录--持续更新_运维_04

 上面我们通常是覆盖配置用的,还有一种情况是直接追加文本到匹配的行的末尾

//先匹配BBB的数据,然后在这个数据的结尾去添加test
sed '/BBB/ s/$/ test/' test.log

shell脚本常用语句记录--持续更新_linux_05

14、将多行数据转换到一行内显示

cat > /tmp/test.log <<EOF
1
2
3
4
5
EOF


//转换 为一行
[root@VM-16-16-centos tmp]# cat /tmp/test.log | xargs
1 2 3 4 5



//再转换为多行
[root@VM-16-16-centos tmp]# cat /tmp/test.log | xargs | xargs -n 1
1
2
3
4
5

15、将匹配到的多个数值做加法运算

cat > /tmp/test.log <<EOF
1
2
3
4
5
EOF


//演示
[root@VM-16-16-centos tmp]# cat /tmp/test.log | awk '{print $n}' | awk '{sum+=$1}END{print sum}'


//返回
15

16、数值排序   去重

cat > /tmp/test.log <<EOF
test 30
Hello 95
Linux 85
EOF


//排序查看
//sort 是排序
//uniq 是去重
[root@VM-16-16-centos tmp]# cat /tmp/test.log | sort | uniq -c
1 Hello 95
1 Linux 85
1 test 30

17、过滤匹配多个对象

cat file | grep -E  'sss|xxx'

18、过滤指定的匹配对象,非模糊匹配

cat /tmp/test.log | grep -w Hello   //-w  一定要完整匹配的才算匹配到

shell脚本常用语句记录--持续更新_linux_06

19、免交互修改用户密码

echo 'xxx' | passwd --stdin root

20、过滤文件或目录

ls -l | grep "^-"    #过滤文件
ls -l | grep "^d" #过滤目录

21、查看包含字符串的文件

//创建测试文件
echo "123 444" >> /tmp/1.txt
echo "123 555" >> /tmp/2.txt


//筛选包含文本的文件
[root@VM-16-16-centos tmp]# grep -r "123" /tmp
/tmp/1.txt:123 444
/tmp/2.txt:123 555

shell脚本常用语句记录--持续更新_centos_07

22、查看当前服务器架构

arch

 

shell脚本常用语句记录--持续更新_linux_08

23、数组值的追加

//定义数组
args=()

//定义变量追加值
i=1
args+=("${i}")
args+=("2")
args+=("3")

//打印数组
[root@VM-16-16-centos tmp]# echo "${args[@]}"
1 2 3

24、去除小括号特殊字符

[root@VM-16-16-centos tmp]# echo '(123)' | cut -d '(' -f2 | cut -d ')' -f1
123

//说明
cut表示切割
-d 表示需要需要使用自定义切割符
-f2 表示对切割后的几块内容选择第2部分输出
-f1 表示对切割后的几块内容选择第1部分输出
| 表示管道

25、shell 批量导入文本数据到数据库

有段时间没有其他语言的环境,只能用shell去把数据写入到数据库

MYSQLCMD="mysql -hhost -uuser -ppasswd db"
CODE="SELECT * FROM table"
echo "${CODE}" | ${MYSQLCMD}

导入数据库时碰到的两种报错

1、ERROR 1406 (22001): Data too long for column ‘name‘ at row 1‘

字段空间太小
我用的varchar 255 ,要导入的数据太长了,这里最大可以设置为65535




2、ERROR 1136 at line 1 Column count doesn`t match value count at row 1


字段数量和插入数据的数量不匹配,可能是字段太少,插入数据超出字段定义了。。
比如我定义了个name,然后你插入了name、sex、xxx等,放不了

26、 查询数据库的数据转换为xls文件

//循环取表名称
for i in `cat host`
do
MYSQLCMD="mysql -u root -pxxxx"
dd=`cat host | grep $i |sed 's/-/_/g' ` //改表名的,可以无视

path="\"/home/mysql/dir/$i.xls\"" //反斜杠转义,保证带双引号的路径,文件存放路径

CODE="select * from dd.$dd into outfile $path" //导出execl文件

echo "${CODE}" | ${MYSQLCMD} //执行命令和mysql交互
done

27、将多个xlsx表 合并成一个execl表,每个表作为sheet页显示

当时我们批量获取的表数据是作为单独的xls表存在的,这里合并到一个表里

25、26、27当时写一个脚本一起用的

import  openpyxl
import os

path="E:/tar/11/" #指定xlsx文件存放路径
src_path=[x for x in os.listdir(path) if x.endswith(".xlsx")] #提交数据的文件,匹配所有

dest_path='C:/Users/刘伟/Desktop/新建文件夹/www.xlsx' #被提交数据的文件

def open_file(i):
src_wb = openpyxl.load_workbook(path+i) #这里表示要打开一个execl文件
dest_wb = openpyxl.load_workbook(dest_path)

sheet_name = src_wb.sheetnames #首先要获取提交的页的名称是什么
sheet_name = sheet_name[0] #因为sheet是一个列表形式的值,我们需要将他取出来

src_sheet = src_wb.get_sheet_by_name(sheet_name) #根据提交的页去获取数据
dest_wb.create_sheet(title=sheet_name,index=0) #因为是完全复制,我们需要在表中创建一个完全相同的sheet页
dest_sheet = dest_wb.get_sheet_by_name(sheet_name) #打开我们创建的sheet页


for i in range(1, src_sheet.max_row+1):
for j in range(1, src_sheet.max_column+1):
dest_sheet.cell(row=i, column=j).value = src_sheet.cell(row=i, column=j).value

dest_wb.save(dest_path)


def main():
#当我们需要添加多个文件到同一个文件时,就还需要再套一层循环
for i in src_path:
open_file(i)


if __name__ == '__main__':
main()

28、感觉不错的正则表达式文章

29、卸载挂载卷 并将容量转换给其他lv卷

umount /目录   //卸载挂载设备

sed -i -e '/挂载相关目录/d' /etc/fstab //将自动挂载的信息删除

lvremove -f 挂载设备 //删除原先的lv卷

lvextend -r --size +10G lv卷设备 //将卷容量扩容到新的lv卷设备
//这里的-r代表的意思是自动加载
//当我们添加资源后会自动重载分区

30、检查输入的ip地址是否规范

#!/bin/bash
function check_ip(){
IP=$1
VALID_CHECK="no"
VALID_CHECK=$(echo $IP|awk -F. '$1 <= 255 && $2 <= 255 && $3 <= 255 && $4 <= 255 {print "yes"}')
if echo $IP |grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null;then
if [[ $VALID_CHECK = yes ]]; then #这里注意一个问题,为什么要用双方括号,因为 如果我们用 [$ss == "dd" ]这样会报一元操作符错误,因为变量可能没有值,使用双括号保证他是有值的就不会报错了
echo "$IP available."
else
echo "xxx"
fi
else
echo "Format error!"
fi
}
check_ip 192.168.1.1 #测试成功案例
check_ip 256.1.1.1 #测试失败案例

31、vsftp服务管理脚本(未验证)

#!/bin/bash
#功能描述(Description):自动部署配置vsftpd服务器,管理FTP服务器,针对RHEL|CentOS系统.
#本地账户访问FTP的共享目录为/common,其中/common/pub为可上传目录.
#匿名账户访问FTP的共享目录为/var/ftp,其中/var/ftp/pub为可上传目录.

#定义变量:显示信息的颜色属性及配置文件路径.
SUCCESS="echo -en \\033[1;32m" #绿色.
FAILURE="echo -en \\033[1;31m" #红色.
WARNING="echo -en \\033[1;33m" #黄色.
NORMAL="echo -en \\033[0;39m" #黑色.
conf_file=/etc/vsftpd/vsftpd.conf

#####从这里开始先将所有需要的功能定义为函数.#####
#定义脚本的主菜单功能.
menu(){
clear
echo "-----------------------------------"
echo "# 菜单(Menu) #"
echo "-----------------------------------"
echo "# 1.安装配置vsftpd. #"
echo "# 2.创建FTP账户. #"
echo "# 3.删除FTP账户. #"
echo "# 4.配置匿名账户. #"
echo "# 5.启动关闭vsftpd. #"
echo "# 6.退出脚本. #"
echo "-----------------------------------"
echo
}

#定义配置匿名账户的子菜单.
anon_sub_menu(){
clear
echo "-----------------------------------"
echo "# 匿名配置子菜单(Menu) #"
echo "-----------------------------------"
echo "# 1.禁用匿名账户. #"
echo "# 2.启用匿名登陆. #"
echo "# 3.允许匿名账户上传. #"
echo "-----------------------------------"
echo
}

#定义服务管理的子菜单.
service_sub_menu(){
clear
echo "-----------------------------------"
echo "# 服务管理子菜单(Menu) #"
echo "-----------------------------------"
echo "# 1.启动vsftpd. #"
echo "# 2.关闭vsftpd. #"
echo "# 3.重启vsftpd. #"
echo "-----------------------------------"
echo
}

#测试YUM是否可用.
test_yum(){
num=$(yum repolist | tail -1 | sed 's/.*: *//;s/,//')
if [ $num -le 0 ];then
$FAILURE
echo "没有可用的Yum源."
$NORMAL
exit
else
if ! yum list vsftpd &> /dev/null ;then
$FAILURE
echo "Yum源中没有vsftpd软件包."
$NORMAL
exit
fi
fi
}

#安装部署vsftpd软件包.
install_vsftpd(){
#如果软件包已经安装则提示警告信息并退出脚本.
if rpm -q vsftpd &> /dev/null ;then
$WARNING
echo "vsftpd已安装."
$NORMAL
exit
else
yum -y install vsftpd
fi
}

#修改初始化配置文件.
init_config(){
#备份配置文件.
[ ! -e $conf_file.bak ] && cp $conf_file{,.bak}

#为本地账户创建共享目录/common,修改配置文件指定共享根目录.
[ ! -d /common/pub ] && mkdir -p /common/pub
chmod a+w /common/pub
grep -q local_root $conf_file || sed -i '$a local_root=/common' $conf_file

#默认客户端通过本地账户访问FTP时
#允许使用cd命令跳出共享目录,可以看到/etc等系统目录及文件.
#通过设置chroot_local_user=YES可以将账户禁锢在自己的家目录,无法进入其他目录.
sed -i 's/^#chroot_local_user=YES/chroot_local_user=YES/' $conf_file
}

#创建FTP账户,如果账户已存在则直接退出脚本.
create_ftpuser(){
if id $1 &> /dev/null ;then
$FAILURE
echo "$1账户已存在."
$NORMAL
exit
else
useradd $1
echo "$2" | passwd --stdin $1 &>/dev/null
fi
}

#删除FTP账户,如果账户不存在则直接退出脚本.
delete_ftpuser(){
if ! id $1 &> /dev/null ;then
$FAILURE
echo "$1账户不存在."
$NORMAL
exit
else
userdel $1
fi
}

#配置匿名账户.
#第一个位置参数为1则将匿名账户禁用.
#第一个位置参数为2则开启匿名账户登陆功能.
#第一个位置参数为3则设置允许匿名账户上传文件.
anon_config(){
if [ ! -f $conf_file ];then
$FAILURE
echo "配置文件不存在."
$NORMAL
exit
fi
#设置anonymous_enable=YES可以开启匿名登陆功能,默认为开启状态.
#设置anonymous_enable=NO可以禁止匿名登陆功能.
#设置anon_upload_enable=YES可以允许匿名上传文件,默认该配置被注释.
#设置anon_mkdir_write_enable=YES可以允许匿名账户创建目录,默认该配置被注释.
case $1 in
1)
sed -i 's/anonymous_enable=YES/anonymous_enable=NO/' $conf_file
systemctl restart vsftpd;;
2)
sed -i 's/anonymous_enable=NO/anonymous_enable=YES/' $conf_file
systemctl restart vsftpd;;
3)
sed -i 's/^#anon_/anon_/' $conf_file
chmod a+w /var/ftp/pub
systemctl restart vsftpd;;
esac
}

#服务管理.
#第一个位置参数为start时启动vsftpd服务.
#第一个位置参数为stop时关闭vsftpd服务.
#第一个位置参数为restart时重启vsftpd服务.
proc_manager(){
if ! rpm -q vsftpd &>/dev/null ;then
$FAILURE
echo "未安装vsftpd软件包."
$NORMAL
exit
fi
case $1 in
start)
systemctl start vsftpd;;
stop)
systemctl stop vsftpd;;
restart)
systemctl restart vsftpd;;
esac
}


######从这里开始调用前面定义的函数.#####
menu
read -p "请输入选项[1-6]:" input
case $input in
1)
test_yum #测试yum源.
install_vsftpd #安装vsftpd软件包.
init_config;; #初始化修改配置文件.
2)
read -p "请输入账户名称:" username
read -s -p "请输入账户密码:" password
echo
create_ftpuser $username $password;; #创建FTP账户.
3)
read -p "请输入账户名称:" username
delete_ftpuser $username $password;; #删除FTP账户.
4)
anon_sub_menu
read -p "请输入选项[1-3]:" anon
if [ $anon -eq 1 ];then
anon_config 1 #禁止匿名登陆.
elif [ $anon -eq 2 ];then
anon_config 2 #启用匿名登陆.
elif [ $anon -eq 3 ];then
anon_config 3 #允许匿名上传.
fi;;
5)
service_sub_menu
read -p "请输入选项[1-3]:" proc
if [ $proc -eq 1 ];then
proc_manager start #启动vsftpd服务.
elif [ $proc -eq 2 ];then
proc_manager stop #关闭vsftpd服务.
elif [ $proc -eq 3 ];then
proc_manager restart #重启vsftpd服务.
fi;;
6)
exit;;
*)
$FAILURE
echo "您的输入有误."
$NORMAL
exit;;
esac

32、docker镜像合并打包

#镜像批量导出
docker save vmware/postgresql-photon:v1.5.1 vmware/photon:1.0 ... | gzip -c > harbor-images.tar.gz

#镜像批量导入
docker load --input harbor-images.tar.gz

33、批量修改不同主机不同密码为相同密码

#!/bin/bash
OLD_INFO=old_pass.txt #需要先创建文件,格式在最下面
NEW_INFO=new_pass.txt
for IP in $(awk '/^[^#]/{print $1}' $OLD_INFO); do
USER=$(awk -v I=$IP 'I==$1{print $2}' $OLD_INFO)
PASS=$(awk -v I=$IP 'I==$1{print $3}' $OLD_INFO)
PORT=$(awk -v I=$IP 'I==$1{print $4}' $OLD_INFO)
NEW_PASS=123456 #$(mkpasswd -l 8) # 随机密码 这个是在安装expect工具时自带的,本脚本需要依赖于expect工具
echo "$IP $USER $NEW_PASS $PORT" >> $NEW_INFO
expect -c "
spawn ssh -p$PORT $USER@$IP
set timeout 2
expect {
\"(yes/no)\" {send \"yes\r\";exp_continue}
\"password:\" {send \"$PASS\r\";exp_continue}
\"$USER@*\" {send \"echo \'$NEW_PASS\' |passwd --stdin $USER\r exit\r\";exp_continue}
}"
done


#####3分割线
vi old_pass.txt
#添加
192.168.1.20 root 123456 22
192.168.1.21 root 123456 22

34、带颜色的文本输出

案例
echo -e "\033[32m文本信息\033[0m"


#这里必须带-e 否则颜色无效

\033 \033 表示文字颜色
[32m 表示背景颜色

35、linux调优

1、关闭selinux:setenforce 0 ;sed -i "s/enforcing/disabled/" /etc/selinux/config

2、关闭firewalld:sys:systemctl stop firewalld;systemctl disable firewalld

3、设置会话连接超时时间和History历史记录配置:在/etc/profile文件中末尾添加2行:

export TMOUT=3600
export HISTTIMEFORMAT="%F %T `whoami` "

4、更新国内yum源

备份yum源 yum install -y wget && mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

下载阿里云yum源 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

清理yum源缓存 创建缓存 查看yum源 更新系统软件

yum -y clean all && yum makecache && yum repolist && yum -y update

5、更新yum源并配置时间同步:` yum install -y wget epel-release net-tools vim ntpdate && /usr/sbin/ntpdate 1.cn.pool.ntp.org` 执行crontab -e命令,添加:`0 * * * * /usr/sbin/ntpdate 1.cn.pool.ntp.org`内容

6、关闭不必要的服务

systemctl stop postfix && systemctl disable postfix && systemctl stop NetworkManager && systemctl disable NetworkManager

7、内核优化

```shell
cat > /etc/sysctl.conf << EOF
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
fs.file-max = 131072
kernel.panic=1
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_no_metrics_save = 1
net.core.netdev_max_backlog = 3072
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_max_tw_buckets = 720000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 5
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_retries1 = 2
net.ipv4.tcp_retries2 = 10
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_syncookies = 1
EOF

sysctl -p
```



```shell
cat >> /etc/security/limits.conf << EOF
* soft nproc 2048
* hard nproc 16384
* soft nofile 8192
* hard nofile 65536
EOF
```

grubby --update-kernel=ALL --args="cnotallow=ttyS0"
reboot

36、生成随机字符串

pwgen 10 -1A0    //这里的10是长度


//举个例子
touch `pwgen 10 -1A0 | sed 's/$/_clsn.html/'`

37、python pip从nexus 拉包

pip install -i  http:ip+端口/simple    xlrd==1.2.0   --trusted-host ip地址

38 查看指定时间区间的日志

//目标查看 2022年 6月 10日志的 下午5点20到5点40的日志

cat 日志文件 | sed -n "/2022-06-10 17:20/,/2022-06-10 17:40/p"

39、根据剩余磁盘空间快速扩容lv卷

#场景,之前分了几个分区,vda这个硬盘上还有剩余资源,我们用剩下的资源去做个分区在扩容到lvm的lv卷上


#! /bin/bash
fdisk /dev/vda<<EOF
n




w
EOF
vgs
vgextend system /dev/vda3
vgs
lvextend -r -L +10G /dev/mapper/system-xxxlv