shell基础回顾

0.vim命令

vim

gg					移动到文档第一行
G   				移动到文档最后一行
:set nu 		显示行号
:set noun 	取消行号
nG					移动到指定n行,例如20G
$						移动到行尾
0						移动到行头
clrt+f 			屏幕向下移动一页
clrt+b 		  屏幕向上移动一页
:%s+word1+word2+g 搜索文本,将word1字符串,替换成word2字符串
x 					向后删除一个字符
X 					向前删除一个字符

shift+d 		删除当前行,光标后的字符
dd 					删除游标所在整行
ndd					删除光比所在向下n列,例如:3dd
yy 					复制游标所在行
p,P 				小p将已复制的数据在光标下一行粘贴,大P则为粘贴在游标上一行
u 					复原前一个动作,回退一步

i 					从当前光标插入
o, O  			小写的o当前光标下一行插入  大写的O当前光标上一行插入
r, R				小写的r替换字符,大写的R

:q!				强制退出不保存
:wq					保存

ZZ 					大写的ZZ,保持后快速退出(需要在esc退出编辑模式下操作)

ctrl+v			光标移动到215.18前,通过上下左右移动选择一块区域,选号后按y 复制,p 粘贴想要的内容


1          2      3      4                              5                     6
tcp        0      0 :::10302                    :::*                        LISTEN
tcp        0      0 ::ffff:172.16.10.205:10302  ::ffff:215.18.157.74:5660   ESTABLISHED
tcp        0      0 ::ffff:172.16.10.205:10302  ::ffff:110.182.143.19:27490 TIME_WAIT
tcp        0      0 ::ffff:172.16.10.205:10302  ::ffff:110.182.143.19:27489 TIME_WAIT
tcp        0      0 ::ffff:172.16.10.205:10302  ::ffff:219.66.163.171:52754 ESTABLISHED
tcp        0      0 ::ffff:172.16.10.205:10302  ::ffff:59.39.132.243:30368  TIME_WAIT

这样复制出来的结果就是:
215.18.157.74:5660
110.182.143.19:27490
110.182.143.19:27489
219.66.163.171:52754
59.39.132.243:30368

1.生成指定文件

#使用dd,if参数指定了输入文件(/dev/zero表示一个无限的全零字节流)
#of参数指定了输出文件的路径和名称(/root/1.log)
#bs参数指定了每次读取和写入的块大小(这里是10MB)
#count参数指定了要复制的块数(这里是1)
dd if=/dev/zero of=/root/1.log bs=10M count=1

2.shell压缩脚本

cat test.sh

#!/bin/bash

#要压缩的目录或者文件
source_dir="/mnt"

#压缩后输入的路径或者文件
output_file="/root/mnt.tar.gz"

#使用tar 命令压缩,通过 --exclude  过滤目录或者文件
tar zcvf "${output_file}" --exclude="/mnt/test"  --exclude="/mnt/1.log" "${source_dir}"

#打包
#tar zcvf 2020.tar.gz *2020*.log

#解压
#tar -zxvf ktgl20201207.tar.gz -C /data/webapp

#不想解压,查看压缩包内容
#tar ztvf ktgl20201207.tar.gz

3.自定义函数别名

#显示当前定义的所有别名
alias

#打开当前用户的.bashrc文件,自定义环境变量、别名和函数等设置
vim ~/.bashrc
#定义函数
testFunc(){
  ps -ef|grep nginx
}


#使变量生效
source ~/.bashrc


#定义别名
alias psnginx=testFunc

4.查看命令cat

#显示行号
cat -n myfile.txt

#显示特殊字符
cat -A myfile.txt

在cat命令后面添加选项-A(或-vET)可以改变输出格式,以显示一些特殊字符的可见表示。
具体来说,-A选项会将以下特殊字符添加到输出中:

  • 非打印字符(不包括换行符和制表符)会以^后接对应的控制字符形式显示。例如,ASCII 值为 1 的字符会显示为 ^A。
  • 行尾的 $ 符号会显示在每行的末尾。
  • 制表符会显示为 ^I。

这个选项通常用于显示一些看不见的特殊字符,以便进行文本分析或调试。

$ cat -A myfile.txt
This is a line of text.^M$
This is another line of text with a tab character. ^I$

#在上面的示例中,^M 表示回车符,^I 表示制表符,$ 表示行尾。

5.find命令

#查找ceph-csi-3.2.0目录下,所有的*log文件
find /ceph-csi-3.2.0/ -name "*log"

#查看/ceph-csi-3.2.0目录下所有*.sh文件每个的大小
#注:xargs组合多个命令的一个工具
find  /ceph-csi-3.2.0/ -type f -name "*.sh" | xargs du -sh

#复制/ceph-csi-3.2.0目录下所有*.sh文件到/root/test下
find  /ceph-csi-3.2.0/ -type f -name "*.sh" -exec cp -a {} /root/test \;



#/ceph-csi-3.2.0目录开始搜索文件,排除目录/ceph-csi-3.2.0/scripts/*,排除文件/ceph-csi-3.2.0/deploy.sh,查找*.sh文件
find /ceph-csi-3.2.0/ -type f -path "/ceph-csi-3.2.0/scripts/*" -o -path "/ceph-csi-3.2.0/deploy.sh" -o -type f -name "*.sh" -print



#比较下面两个打包的区别
#第一个是打包成一个文件
find /ceph-csi-3.2.0/ -type f -path "/ceph-csi-3.2.0/scripts/*" -o -path "/ceph-csi-3.2.0/deploy.sh" -o -type f -name "*.sh" -print | xargs tar zcvf allSh.tar.gz

#第二个是打包成多个文件
find /ceph-csi-3.2.0/ -type f -path "/ceph-csi-3.2.0/scripts/*" -o -path "/ceph-csi-3.2.0/deploy.sh" -o -type f -name "*.sh" -print -exec tar zcvf {}.tar.gz {} \;


6.ln 软链接和硬链接

#软链接
ln -svf /ceph-csi-3.2.0/allSh.tar.gz /root/
● -s:创建软链接(Symbolic Link),而不是创建硬链接。
● -v:显示详细的输出,即在创建链接时显示正在进行的操作。
● -f:强制执行操作,即如果目标文件已存在,则覆盖它。


#硬链接
ln /ceph-csi-3.2.0/allSh.tar.gz /root/

在Linux中,ln命令用于创建链接(link)文件。其中有两种类型的链接:软链接(Symbolic Link)和硬链接(Hard Link)。它们之间有以下区别:

  1. 路径类型:软链接是一个指向目标文件的路径名,而硬链接是一个指向目标文件的物理副本。
  2. 文件类型:软链接被视为一个独立的文件,它具有自己的 inode 和文件权限。硬链接是文件系统中原始文件的另一个名称,实际上它们共享相同的 inode 和文件权限。
  3. 跨文件系统:软链接可以跨越不同的文件系统,因为它们只是包含目标文件路径的文本文件。硬链接只能在同一文件系统内工作,因为它们依赖于 inode。
  4. 目标更新:如果目标文件被重命名、删除或移动,软链接将失效,而硬链接仍然有效,因为它们直接指向目标文件的物理副本。
  5. 目录链接:软链接可以链接到目录,而硬链接不能链接到目录。
  6. 多个链接:对于硬链接,可以有多个链接指向同一文件,而软链接只能有一个链接指向目标文件。

总之,软链接是指向目标文件路径的独立文件,可以跨文件系统并且保留原始文件的路径和权限信息。硬链接是原始文件的另一个名称,具有相同的inode和权限,不能跨越文件系统,并且在目标文件更改时仍然有效。

使用ln命令创建链接时,如果不指定任何选项,默认情况下会创建硬链接。要创建软链接,可以使用ln -s选项。

7.文件和目录对比

diff			文件内容对比命令(案例:diff 1.txt 2.txt)
du				查看文件或目录使用空间大小
basename	过滤出路径下面最后的文件名或目录
dirname		从文件名中删除最后一个组成部分
df				查看系统硬盘占用空间情况 (案例:df -TH)
df -i			查看磁盘inode使用空间

#查看目录下,低于100K的文件数量
find /mnt -type f -size -100k | wc -l

#删除低于100K,过多小文件
find /mnt -type f -size -100k |  xargs rm -f



[root@k8s-master01 jtpv]# basename /root/jtpv/pv.yaml
pv.yaml
[root@k8s-master01 jtpv]# dirname /root/jtpv/pv.yaml
/root/jtpv


8.目录或文件权限

[root@news-static ~]# ls -l 1.html
-rw-r--r--. 1 root root 0 1225 2019 1.html

[root@news-static ~]# ls -ld nginx-1.23.2
drwxr-xr-x. 9 1001 1001 4096 1130 2022 nginx-1.23.2



r	w	x
4	2	1
读 写 执or进入
0644/-rw-r--r--	#文件  
0755/drwxr-xr-x	#目录


0644+0022=0666 文件最大权限666
0755+0022=0777 目录最大权限777


umask
	0022 #第一位0: 表示这是一个八进制数


[root@news-static ~]# umask
0022
[root@news-static ~]# ls -l 1.html
-rw-r--r--. 1 root root 0 1225 2019 1.html


[root@k8s-master01 ~]# diff 1.txt 2.txt
12a13
> 123



chown			更改文件所有者以及所有组,常用-R 是目录内所有文件都授权
chattr +i	锁定文件
lsattr		显示文件或目录的扩展属性的命令
chattr +a	只允许增加内容


[root@news-static ~]# lsattr 2.txt
-------------e- 2.txt
[root@news-static ~]# chattr +i 2.txt
[root@news-static ~]# lsattr 2.txt
----i--------e- 2.txt
[root@news-static ~]# chattr -i 2.txt
[root@news-static ~]# lsattr 2.txt
-------------e- 2.txt
[root@news-static ~]#



[root@news-static ~]# chattr +a 2.txt
[root@news-static ~]# lsattr 2.txt
-----a-------e- 2.txt
[root@news-static ~]# echo 3 > 2.txt
-bash: 2.txt: 不允许的操作
[root@news-static ~]# echo 3 >> 2.txt
[root@news-static ~]# cat 2.txt
123
3
[root@news-static ~]#


9.遍历目录

[root@news-static mydir]# cat test.sh
#!/bin/bash

directory=$1

# 使用 find 命令递归遍历指定目录下的所有文件和子目录
find "$directory" -print | while read file; do
    if [[ -d "$file" ]]; then  # 判断是否为目录
        echo "Dire: $file"
    elif [[ -f "$file" ]]; then  # 判断是否为文件
        echo "File: $file"
    fi
done


[root@news-static mydir]# /tmp/mydir/test.sh /tmp/mydir
Dire: /tmp/mydir
File: /tmp/mydir/boge.sh
File: /tmp/mydir/test.sh
Dire: /tmp/mydir/dir1
Dire: /tmp/mydir/dir1/dir2
Dire: /tmp/mydir/dir1/dir2/dir3
File: /tmp/mydir/dir1/dir2/dir3/file3.log
File: /tmp/mydir/dir1/dir2/file2.log
File: /tmp/mydir/dir1/file1.log
[root@news-static mydir]#



[root@news-static mydir]# cat boge.sh
#!/bin/bash

listFile() {
  local tempDir=$1

# 使用 find 命令递归遍历指定目录下的所有文件和子目录
  find "$tempDir" -print | while read file; do
      if [[ -d "$file" ]]; then  # 判断是否为目录
          echo "Dir: $file"
      elif [[ -f "$file" ]]; then  # 判断是否为文件
          echo "Fil: $file"
      fi
  done
}
#运行函数
listFile $1


[root@news-static mydir]# /tmp/mydir/test.sh /tmp/mydir
Dire: /tmp/mydir
File: /tmp/mydir/boge.sh
File: /tmp/mydir/test.sh
Dire: /tmp/mydir/dir1
Dire: /tmp/mydir/dir1/dir2
Dire: /tmp/mydir/dir1/dir2/dir3
File: /tmp/mydir/dir1/dir2/dir3/file3.log
File: /tmp/mydir/dir1/dir2/file2.log
File: /tmp/mydir/dir1/file1.log
[root@news-static mydir]#

10.处理僵尸进程

生产案例:
zombie 僵尸进程的发现,查看,及解决的步骤

1、通过 top 查看是否存在zombie 僵尸进程

[root@localhost ~]# top
top - 14:53:32 up 86 days, 9:47, 2 users, load average: 2.09, 1.91, 1.79
Tasks: 1248 total, 1 running, 1246 sleeping, 0 stopped, 1 zombie
Cpu(s): 16.5%us, 7.3%sy, 0.0%ni, 72.9%id, 3.1%wa, 0.0%hi, 0.2%si, 0.0%st

2、查看具体是哪个进程
[root@localhost ~]# ps -A -o stat,ppid,pid,cmd | grep -e “1
Z 2216 31127 [abrt-server]

3、查看僵尸进程是什么应用
[root@localhost ~]# lsof -p 2216

4、kill僵尸进程
[root@localhost ~]# kill -9 2216

11.shell并发快速查询在线IP

cat select_ip.sh

#!/bin/bash
#__author__: boge

#不在线ip记录
> ./ip_offline.txt


#在线ip记录
> ./ip_online.txt


#传入网段3个参数案例:	10.0.1 1 254
if [ $# -ne 3 ];then
	echo "Usage: bash $0 10.0.1 1 254"
	exit 3
fi

pingnum=`seq $2 $3`
for i in $pingnum
do
{
  ping -c 1 -i 0.1 -W 1 $1.$i &> /dev/null
  if [ $? -eq 0 ];then
    echo "IP:   $1.$i is online."
    echo "$1.$i" >> ./ip_online.txt
  else
    echo "IP $1.$i is offline."|tee -a ./ip_offline.txt
  fi
}&
done

#等待所有子进程返回结果后在退出主进程
wait

12.循环for和while

#for循环输出1到10的数字
[root@news-static ~]# for i in `seq 10`;do echo "$i";sleep 1;done


#无限循环输出
[root@news-static ~]# cat while.sh
#!/bin/bash

while true
do
  date
  sleep 1
done


#while 循环输出1到10的数字
[root@news-static ~]# cat while.sh
#!/bin/bash

counte=1

while [ $counte -le 10 ]
do
  echo $counte
  counte=$((counte + 1))
  sleep 0.5
done

11.shell中的列表和字典

-------------
SHELL数组(实现列表)
-------------
# family=(aaa bbb ccc)    <--- 定义数组
# echo ${#family[*]}     <--- 取数组里变量长度
3
# echo ${family[0]}     <--- 取数组第一个变量
aaa
# echo ${family[1]}     <--- 取数组第二个变量
bbb
# echo ${family[2]}     <--- 取数组第三个变量
ccc
# echo ${family[*]}     <--- 取数组里所有变量
aaa bbb ccc
# echo ${family[*]:2}     <--- 去掉数组里的前两个值,保持取最后一个值
ccc

脚本示例:
# vim test.sh
#!/bin/bash
family=(     # or 也可以这样定义  family=(aaa bbb ccc)
aaa 
bbb 
ccc
)

for name in ${family[*]}   #第一种方法,常规for循环取值的方式
do
echo $name
done
echo "================="
for ((name=0;name<${#family[*]};name++))   #第二种方法
do
echo ${family[name]}
done

执行结果:
[root@nfs-server scripts]# bash test.sh 
aaa
bbb
ccc
=================
aaa
bbb
ccc




实现"字典"my_config=(
  shanghai+http://10.0.1.201+boge+devops1
  beijing+http://10.0.1.202+boge+devops2
  hongkong+http://10.0.1.203+boge+devops3
)


for r in `echo ${regions}`
do
  export MY_REGION=`echo ${my_config[@]}|tr " " "\n"|grep -w $r|awk -F+ '{print $1}'`
  export MY_URL=`echo ${my_config[@]}|tr " " "\n"|grep -w $r|awk -F+ '{print $2}'`
  export MY_USERNAME=`echo ${my_config[@]}|tr " " "\n"|grep -w $r|awk -F+ '{print $3}'`
  export MY_PASSWORD=`echo ${my_config[@]}|tr " " "\n"|grep -w $r|awk -F+ '{print $4}'`

  echo "====== $r START  ======"
  echo $MY_URL
  echo $MY_USERNAME
  echo $MY_PASSWORD
  echo $MY_REGION
  echo "====== $r END  ======"
done


# 另外一种实现字典的形式
#!/bin/bash


test='
{
  "aaa": 1,
  "bbb": 2,
  "ccc": 3
}
'

echo $test|jq -r ".aaa"

12.运维服务菜单选项

1. if elif else脚本

#!/bin/bash

# 这个脚本演示了如何使用 case 语句根据用户输入执行不同的操作

echo "请输入你的选择[1 - 4]:"
echo "1. 开始服务"
echo "2. 停止服务"
echo "3. 重启服务"
echo "4. 退出服务"

read choice

if [[ $choice -eq 1 ]];then
    echo "开始服务了"
elif [[ $choice -eq 2 ]];then
    echo "停止服务了"
elif [[ $choice -eq 3 ]];then
    echo "重启服务了"
else
    echo "退出服务了"
fi

2.使用case脚本:

#!/bin/bash

# 这个脚本演示了如何使用 case 语句根据用户输入执行不同的操作

echo "请输入你的选择[1 - 4]:"
echo "1. 开始服务"
echo "2. 停止服务"
echo "3. 重启服务"
echo "4. 退出服务"

read choice

case $choice in
    1)
        echo "Starting service..."
        # 执行启动操作的命令
        ;;
    2)
        echo "Stopping service..."
        # 执行停止操作的命令
        ;;
    3)
        echo "Restarting service..."
        # 执行重启操作的命令
        ;;
    4)
        echo "Exiting service..."
        exit
        ;;
    *)
        echo "Invalid choice"
        ;;
esac

13.标准的运维工具脚本

#!/bin/bash

# 这个脚本演示了如何使用 getopts 函数解析命令行参数
if [ $# -eq 0 ];then
    echo "Usage: bash $0 (-A|-D|-L) -e (1h or more) -t (admin|view) -u boge"
    exit 1
fi


# 默认值
ACTION=""
EXPIRY=""
USER_TYPE=""
USER_NAME=""

# 解析命令行参数
while getopts "ADLe:t:u:" OPTION; do
    case $OPTION in
        A)
            ACTION="add-test $1"
            ;;
        D)
            ACTION="del-test $1"
            ;;
        L)
            ACTION="list-test $1"
            ;;
        e)
            EXPIRY="$OPTARG"
            [[ $OPTARG =~ ^[1-9][0-9]*h$ ]] || { echo "'-e' must be set like '2h, 5h, 50000h, ...'"; exit 1; }
            ;;
        t)
            USER_TYPE="$OPTARG"
            [[ $OPTARG =~ ^(admin|view)$ ]] || { echo "'-t' can only be set as 'admin' or 'view'"; exit 1; }
            ;;
        u)
            USER_NAME="$OPTARG"
            ;;
        ?)
            echo "Invalid option: -$OPTARG"
            exit 1
            ;;
    esac
done

function add-test(){
# 打印解析的参数
echo "ACTION: $ACTION"
echo "EXPIRY: $EXPIRY"
echo "USER_TYPE: $USER_TYPE"
echo "USER_NAME: $USER_NAME"
}

function del-test(){
# 打印解析的参数
echo "ACTION: $ACTION"
echo "EXPIRY: $EXPIRY"
echo "USER_TYPE: $USER_TYPE"
echo "USER_NAME: $USER_NAME"
}

function list-test(){
# 打印解析的参数
echo "ACTION: $ACTION"
echo "EXPIRY: $EXPIRY"
echo "USER_TYPE: $USER_TYPE"
echo "USER_NAME: $USER_NAME"
}

${ACTION}

参考博客:博哥爱运维
https://www.toutiao.com/article/7271959603280265739?wid=1698656801777


  1. Zz ↩︎

你可能感兴趣的:(linux,shell)