admin管理员组

文章数量:1532343

shell 编程


变量

定义变量

  • 变量名与变量内容以一个=连接,且等号两边不能有空格

  • 变量名称只能是英文字母、数字与下划线,但是不能以数字开头

  • 变量内容若有空格可使用双引号 " 或单引号' 将变量内容组合起来

    • 单引号' 为强引用,会将引号内的内容原样显示出来
    • 双引号 "为弱引用,会保持引号内特殊符号的原有特性
    song=1
    # 双引号保持特殊符号的原有特性
    s1="i am $song"
    echo $s1
    >i am 1
    
    # 单引号会将引号内的内容原样显示出来
    s2='i am $song'
    echo $s2
    >i am $song
    
  • 可用转意符 \ 将特殊符号(如 [Enter], $, \, 空格符, 等)变成一般字符

  • 在一串命令中,还需要藉由其他的命令提供的信息,可以使用以下两种方式

    # `命令`
    echo `ip a`
    # $(命令)  推荐
    echo $(ip a)
    
  • 增加变量的内容时,则可用以下两种方式

    song=1
    song=${song}55
    echo $song
    >155
    
  • 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量export song

    • 使自定义的变量 成为 环境变量,环境变量可以被向下继承(子进程 仅会继承父 shell 的环境变量, 不会继承父 shell 的自定义变量),并且 export 声明的环境变量只能被其子 shell 继承使用,不能被 父 shell 继承使用
    #例子
    [root@kube-master py3]# bash           # 打开一个子 shell
    [root@kube-master py3]# export a=hello # 在 子 shell 声明一个环境变量
    [root@kube-master py3]# bash           # 在子 shell 中再打开一个 子 shell
    [root@kube-master py3]# echo $a        # 变量可以生效
    hello
    [root@kube-master py3]# exit           # 退出 子 shell 的 子 shell
    exit
    [root@kube-master py3]# exit           # 退出 子 shell
    exit
    [root@kube-master py3]# echo $a        # 在 当前 shell 中, 其子 shell 声明的环境变量是无效的
    
    [root@kube-master py3]# 
    
  • 通常大写字符为系统默认变量,自定义变量可以使用小写字符,方便判断 (纯粹个人习惯) ;

  • 取消变量的方法为使用unset 变量名称 unset song

环境变量

这种变量是会影响bash环境操作的,会在真正进入系统前由一个bash程序读入到系统中。通常都环境变量的名字以大写字符命名。

1、常见的环境变量
  • PATH 系统命令存放目录

  • HOME 当前用户的家目录

  • MAIL

  • SHELL

  • PWD 当前所在目录

  • USER 当前用户

  • UID 当前用户的uid

  • ID 当前用户的组id

  • RANDOM 随机数

  • PS1 提示字符

    可用的提示字符的含义

    • \d :可显示出“星期 月 日”的日期格式,如:“Mon Feb 2”
    • \H :完整的主机名称。如 www.sharkyun
    • \h :仅取主机名称在第一个小数点之前的名字, www
    • \t :显示时间,为 24 小时格式的“HH:MM:SS”
    • \T :显示时间,为 12 小时格式的“HH:MM:SS”
    • \A :显示时间,为 24 小时格式的“HH:MM”
    • \@ :显示时间,为 12 小时格式的“am/pm”样式
    • \u :目前使用者的帐号名称,如“dmtsai”;
    • \v :BASH 的版本信息
    • \w :完整的工作目录名称,由根目录写起的目录名称。但主文件夹会以 ~ 取代;
    • \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
    • \# :下达的第几个指令。
    • \$ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $

    颜色表

    前景 背景 颜色

    30 40 黑色

    31 41 红色

    32 42 绿色

    33 43 黄色

    34 44 蓝色

    35 45 紫红色

    36 46 青蓝色

    37 47 白色

    代码 意义

    0 OFF

    1 高亮显示

    4 underline

    7 反白显示

    8 不可见

    设置PS1

    设置颜色 [\e[F;Bm\] 其中“F”为字体颜色,编号30~37;“B”为背景色,编号40~47

    取消设置 [\e[m\] 如果不取消 后面的所有内容都会是这个颜色

    # 可以显示git状态的
    function parse_git_dirty {
    [[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
    }
    function parse_git_branch {
    git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/git:\1$(parse_git_dirty)/"
    }
    export PS1="\[\e[36m\]○\[\e[33m\]\$(parse_git_branch)\[\e[m\] {\[\e[36m\]>\#< \[\e[34m\]\u@\h \e[33m\]\[\e[m\]}\n \[\e[31m\]\w○\$ →\[\e[m\]"
    
2、列出shell环境下的所有环境变量及其内容
  • env 是 environment (环境) 的简写,所有的环境变量(包含自定义的环境表里)
  • set 列出系统中所有的变量,包括自定义的变量
3、bash 的环境变量文件
  • longin shell
    取得shell时需要完整的登入流程;特点是登入时需要用户帐号和密码
  • no-login shell
    取得shell时不需要再次输入帐号和密码的情况下,所得到的 shell

longin shell 会读取以下两个文件:

  1. ·/etc/profile· :这是系统整体设定,最好不要修改
  2. ·~/.bash_profile~/.bash_login~/.profile` :属于个人的配置文件

/etc/profile 会主动依序调用以下脚本文件:

  • /etc/inputrc :定义快捷键
  • /etc/profile.d/*sh :定义bash操作接口颜色、语系、命令别名等
  • etc/locale.conf :定义系统的默认语系

bash 在读完 /etc/profile 后,接下来会读取以下3个文件,且只会读去一个,会按照以下顺序优先读取

~/.bash_profile  //会调用 ~/.bashrc,也会有新的环境变量在下面的文件中被添加
~/.bash_login
~/.profile

最终,~/.bashrc 才是最后被读入到系统环境中的文件

让这些环境变量文件中的变量等设置及时在当前 shell 终端中生效,有下两种方式

source ~/.bashrc 
或者
. ~/.bashrc
no-longin shell  当取得no-longin shell时,该shell仅会读取 ~/.bashrc 文件 而~/.bashrc最后又会调用 /etc/bashrc

/etc/bashrc 的作用:

• 依据不同的UID定义出 umask
• 依据不同的UID定义出提示符(就是PS1变量)
• 呼叫 /etc/profile.d/*.sh 的设定

其他的相关配置文件

/etc/man.config
这个文件最重要的就是定义了MANPATH 这个变量,它定义了man page 的路径;在以tarball的方式安装软件时有用
~/.bash_history
历史命令记录文件;记录的数量与HISTFILESIZE变量有关。在/etc/profile
~/.bash_logout
记录了当我注销bash后,系统再帮我做完什么动作后才离开的。

4、预定义变量

预定义的特殊变量有着特殊的含义,用户不可以更改,所有的预定义变量都由 $ 符号和另外一个符号组成

# 常用的预定义特殊变量如下
$$ 当前进程PID
$? 命令执行后的返回状态.0 为执行正确,非 0 为执行错误 
$# 位置参数的数量
$* 所有位置参数的内容   
$@ 显示所有的参数
$! 上一个后台进程的PID (wait命令中使用,后面讲)
5、从键盘的输入给变量赋值 read
read [-pt] 变量名
选项参数:
-p :后面可以接提示字符!
-t :后面可以接等待的『秒数!』,比如 -t 5 提示用户输入信息时间是 5 秒钟,超过 5 秒钟,程序就继续向下运行

例子:
read -p “请输入你的姓名” name

echo "你的姓名是: $name"
6、变量的删除、取代和替换
  • 删除

    • 从后往前删除${变量%匹配的内容}
    • 从前往后删除${变量#匹配的内容}
  • 替换(就是设置默认值)

    最常用的是var=${str:-expr} 后面的expr就是设置的默认值

7、时间变量的计算
// 计算 3 小时之后是几点几分
date +%T -d '3 hours'

// 任意日期的前 N 天,后 N 天的具体日期
date +%F -d "20190910 1 day"
date +%F -d "20190910 -1 day"

// 计算两个日期相差天数, 比如计算生日距离现在还有多少天
d1=$(date +%s -d 20180728)
d2=$(date +%s -d 20180726)
echo $((   (d1-d2)     /   86400          ))

# 输出 
2
8、位置变量

位置变量也属于预定义的变量
位置变量针对于脚本来说
位置变量是根据命令出现在命令行上的位置来确定的变量,在shell调用过程中,会按参数所在的位置进行调用。

假如脚本中使用了一个位置变量,但是执行脚本的时候,传入了多个参数,程序并不会报错。但是执行的时候只传入了一个参数,同样不会报错,后面的位置参数不会被赋值

脚本基础

脚本的执行方式

  • source 脚本 在父进程中执行脚本代码
  • sh 脚本 在子进程中执行脚本代码,相当于打开了一个子shell,一个全新的环境
  • ./脚本

set

  • set -u

    • 当脚本中遇到未定义的变量时,默认是忽略。有时候这并不是开发者想要的。假如有未定义的变量,应该报错,并且终止脚本继续运行。
  • set -e

  • 在脚本执行中,有任何命令的返回值是非 0 的情况,则正在运行的脚本则会退出。对于一组含有管道的命令无效。

    # 设置之前
    [root@kube-master set]# cat set-e-before.sh
    #!/bin/sh
    
    foo
    echo "继续执行"
    [root@kube-master set]# sh set-e-before.sh
    set-e-before.sh: line 3: foo: command not found
    继续执行
    
    # 设置之后
    [root@kube-master set]# cat set-e-after.sh
    #!/bin/sh
    
    set -e
    
    foo
    echo "继续执行"
    [root@kube-master set]# sh set-e-after.sh
    set-e-after.sh: line 5: foo: command not found
    
    # 对于含有管道的命令无效
    #!/usr/bin/env bash
    set -e
    foo | echo "shark"    # 注意这里有管道符
    echo  "程序会继续运行"
    [root@kube-master set]# sh set-e.sh
    shark
    set-e.sh: line 2: foo: command not found   # 这是报错信息
    程序会继续运行
    
    # foo 不是 shell 中的命令,执行会报错,但是其后面有个管道,最终管道后的 echo 命令执行成功了,这种情况下 脚本会继续执行。
    
  • set -o pipefail

    • 需要和 set -e 配合使用。如果设置,如果管道中的所有命令都成功退出,整条命令的返回值才是 0。否则返回非 0
      默认情况下禁用此选项
    # 设置 set -o pipefail 后,此时脚本就会终止运行
    set -e
    set -o pipefail
    foo |echo ''
    echo shark
    [root@kube-master set]# sh set-e-pipefail.sh
    
    set-e-pipefail.sh: line 4: foo: command not found
    

基础语法

判断

  • test
    测试的标制代表的意义
    判断是否存在
    例子 test -e filename
    -e该文件名是否存在
    -f该文件名是否存在且为文件
    -d该文件名是否存在且为目录
    检测文件权限
    例子 test -r filename
    -r检测该文件名是否存在且可读
    -w检测该文件名是否存在且可写
    -x检测该文件名是否存在且可执行
    -u检测该文件名是否存在且具有suid属性
    -g检测该文件名是否存在且具有sgid属性
    -k检测该文件名是否存在且具有sticky bit属性
    -s检测该文件名是否存在且为非空白文件
    两文件比较
    例子 test file1 -nt file2
    -nt判断文件1是否比文件2新
    -ot判断文件1是否比文件2旧
    -ef判断文件1与文件2是否为同一文件(inode号是否一致),可用在判断硬链接上
    两个整数之间的判断
    例子 test n1 -eq n2
    -eq相等
    -ne不等
    -gt大于
    -lt小于
    -ge大于等于
    -le小于等于
    字符串及变量判断
    test -z string判断长度是否为0,若string 为空字串,返回true
    test string
    test !-z string
    判断长度是否为0,若string 为空字串,返回falseww’w
    test str1 == str2判断str1是否等于str2,相等则返回true
    test str1 != str2判断str1是否不等于str2,相等则返回false
    在shell中以下两种情况,变量的长度均视为0
    1、变量未定义
    2、变量定义了,但赋值为空字符串,如a=''
    多重条件判断
    例如:test -r filename -a -x filename
    -a和 两个条件同时成立
    -o或 两个条件有任意一个成立
    !取反
  • 判断符号[ ]
    • 在中括号中的每个元素之间都需要用空格来分隔
    • 在中括号内的变量最好都用双引号括起来
    • 可以跟的选项与test一致,例如[ -f filename]
    # 错误示范
    # 定义变量
    name="shark ops"
    
    # 开始测试值是否相等
    [ ${name} == "xiguatian" ]
    
    # 报错
    bash: [: too many arguments
    
    # 正确的写法
    [ "${name}" == "xiguatian" ]
    

逻辑语句

1、if判断
# 单层
if [ 判断条件 ];then
  条件成立时执行的语句
fi

# 含有else的单层结构
if [ 判断条件 ];then
  条件成立时执行的语句
else
  条件不成立时执行的语句
fi

# 多条件判断,elif可以有多个
if [ 判断条件1 ];then
  条件1成立时执行的语句
elif [ 判断条件2 ];then
  条件2成立时执行的语句
else
  条件都不成立时执行的语句
fi

# 如果在判断中使用正则,则要将条件用 [[ ]] 括起来,使用 =~ 来进行匹配,如果不想匹配 则使用[[ ! 条件 ]]
#例子
#!/usr/bin/env   sh
name=shark
# 匹配
if [[ "$name"  =~  [a-z]+ ]];then
   echo "ok"
fi
# 不匹配
if [[ ! "$name" =~ [0-9]+ ]];then
   echo  "good"
fi

# 嵌套,在一个 if 判断中还可以嵌套多个if判断或其他语句,只要结构完整就好
2、case语句
# 基本语法
case  $变量名称 in       <==关键字为 case ,还有变量前有钱字号
  "第一个变量的值")       <==每个变量内容建议用双引号括起来,关键字则为小括号 )
    程序段
    ;;                  <==每个类别结尾使用两个连续的分号来处理!
  "第二个变量的值")
    程序段
    ;;
  *)                    <==最后一个变量内容都会用 * 来代表所有其他值
    不包含第一个变量内容与第二个变量内容的其他程序运行段
    exit 1
    ;;
esac                    <==反过来写,结束当前语句结构!

# 例子,变量值不仅可以是一个,也可以是多个
#!/bin/bash
cat << EOF
m|M) show memory usages;
d|D) show disk usages;
q|Q) quit
EOF
read -p "Your choice" choice
case $choice in
m|M)
        free -m
        ;;
d|D)
        df -h
        ;;
q|Q)
        exit
        ;;
*)
        eco "Invalid input"
        ;;
esac
3、while语句
# 基础语句
while [ condition ]  ==>中括号内的状态就是判断式
do                   ==> do 是循环的开始!
    命令或者代码
    命令或者其他逻辑语句
done                 ==> done 是循环的结束

#每次循环体执行完,while 都会检查条件是否为真,为真继续循环,否则终止循环
#所以在使用while循环时,如果不想进入无限循环,按情况添加条件

# read
# read可以同时添加多个变量
[root@sharkyun ~]# read id name age
1 shark 18
[root@sharkyun ~]# echo $age
18
[root@sharkyun ~]# echo $id  $name
1 shark
# read默认分割符为空格,可以修改,IFS就是存储分割符的
[root@sharkyun ~]# old_ifs=$IFS; IFS=','
[root@sharkyun ~]# read id name age
2, xiguatian, 20
[root@sharkyun ~]# echo "$id| $name| $age"
2|  xiguatian|  20
[root@sharkyun ~]# export IFS=$old_ifs
[root@sharkyun ~]# read id name age
2, xiguatian, 20
[root@sharkyun ~]# echo "$id| $name| $age"
2,| xiguatian,| 20
[root@sharkyun ~]# read id name age
2,xiguatian,20
[root@sharkyun ~]# echo "$id| $name| $age"
2,xiguatian,20| |

# while read
$ cat db.sql
1 shark 18
2 xiguatian 20

$ cat  while-read-m.sh
while read id name age
do
    echo "$id | $name | $age"
done < db.sql    # 读取文件里的内容

$ sh while-read-m.sh

1 | shark | 18
2 | xiguatian | 20

4、for语句
for 变量 in 被循环对象
do
执行语句
done
# for 循环中变量的取值
# a. 从一组字符串中取值
for  var     in    one    two    three   four   five 
do
    echo    "****************************"
    echo   '$var   is '    $var
done

# b. 从位置变量中取值
for    var
do
    echo  '-----------------------------'
    echo   '$var   is '    $var
done

 {>15< root@song ~/test}$→sh var.sh 1 2 3 4 5
-----------------------------
$var   is  1
-----------------------------
$var   is  2
-----------------------------
$var   is  3
-----------------------------
$var   is  4
-----------------------------
$var   is  5

# c. 从累计变化的格式中取值
#!/bin/bash 

for    ((var=1;var<=10;var++))
do
    echo   "------------------------" 
    echo   '$var   is '    $var
done

# d. 从命令结果中取值
#!/bin/bash
for   var   in   $(cat    file.txt)
do
    echo  " ------------------------" 
    echo   '$var   is '    $var
done
5、数值运算方式
# 第一种 
➜  ~ n=1
➜  ~ let n++
➜  ~ echo $n
2

# 第二种
➜  ~ (( n++ ))
➜  ~ echo $n
3

# 第三种
➜  ~ a=2
➜  ~ b=3
➜  ~ let f=a+b
➜  ~ echo $n
3
➜  ~ echo $f
5

➜  ~ let f = a + b     ==> 错误
zsh: bad math expression: operand expected at `='
# 第三种变式
➜  ~ let "f = a + b"
➜  ~ echo $f
5
6、break和continue
  • break 就是退出循环,循环不再继续了。假如是嵌套的循环,就是退出当前层级的循环。
  • continue 是停止本次循环体内的代码,继续进行下一次循环。
1、单层循环的break

示例代码


运行结果

2、单层循环的continue

示例代码


执行结果

3、 多层循环的 break

示例代码

执行结果

数组

# 定义一个数组
var=(wukong bajie shaseng)

echo ${var[2]} //显示数组中索引号为 2 的值,索引号从 0 开始
输出 shaseng

echo ${var[*]}  //显示数组中所有的值
输出 wukong bajie shaseng

# 定义数组,并且其值从命令的结果中获取
# 把文件中的每一行作为数组中的一个值
line=(`cat /etc/passwd`)
# declare 声明关联数组

# 声明
declare -A  数组名称

# 添加值
# 每次添加一个值,可以追加 var[key]=value
[shark@sharkyun ~]$ info[name]=shark
[shark@sharkyun ~]$ info[age]=18
[shark@sharkyun ~]$ echo ${info[name]}  # 显示索引对应的值
shark
[shark@sharkyun ~]$ echo ${info[age]}
18  
# 一次添加所以的值,不可以追加,每次都会覆盖上次的值,每个值之间使用 空格 隔开  var=([key1]="value1" [key2]="value2")
[root@kube-master script]# declare -A color
[root@kube-master script]# color=(["red"]="#ff0000", ["green"]="#00ff00")
[root@kube-master script]# echo ${color[*]}
#ff0000, #00ff00
[root@kube-master script]# color=(["a"]="#ff")   # 这样会覆盖原来的值,因为这是在重新定义变量  color
[root@kube-master script]# echo ${color[*]}
#ff
[root@kube-master script]# color=(["b"]="ff")
[root@kube-master script]# echo ${color[*]}
ff
[root@kube-master script]# color[c]="#cc"
[root@kube-master script]# echo ${color[*]}
ff #cc
[root@kube-master script]# echo ${!color[*]}  # 获取所有的 索引号
b c
[root@kube-master script]# echo ${#color[*]}  # 统计数组中有多少个键值对
2

# 删除
[root@kube-master arry]# unset info[name]
[root@kube-master arry]# echo ${!info[*]}
age

函数

就是对代码的封装,通常会完成一个功能,而出现的一种组织和代码的方式。

  1. 减少代码重复编写,从而也提高了代码的可复用率。
  2. 程序逻辑解构清晰。
  3. 可以使程序代码更易读,便于管理维护。
  4. 是模块化编程思想的基础。

函数必须先定义才可以使用

1、定义函数

# 方法一,推荐
函数名(){
  代码
}

# 方法二
function 函数名 (){
  代码
}

2、调用函数

# 无参函数调用,直接使用函数名

# 有参函数调用方法,函数传参时和脚本的传参一样
函数名 参数1 参数2

# 例子
# 定义函数
say_you_say_any(){
    echo "我看过很多书,但都没有 "$1" 好看^_^"
}

# 例子,调用有参函数
say_you_say_any  xinyi

3、函数参数

在Shell中调用函数时可向其传递参数。在函数体内部通过 $n 的形式来获取参数的值,如:$1 表示第1个参数,$2 表示第2个参数…;当n>=10时,表示为 ${n},如:${10}、${11}

位置参数作用
$n利用参数向程序中传递需要调用的值n为数字,n≤9直接用数字,n≥10都需要用{}包含:$0 表示命令本身 $1-$9 表示第1-9个参数 ${10} 表示第10个参数
$*表示命令行中所有的参数,所有参数看作一个整体
$@表示命令行中的所有参数,每个参数区分对待
$#表示命令行中所有参数的个数(不统计$0
预定义变量作用
$?最后一次执行的命令所返回的状态:若变量值为0,说明上一个命令正确执行若变量值为非0,说明上一个命令执行不正确
$$当前进程的进程号(PID)
$!后台运行的最后一个进程的进程号(PID)
# 示例
# 定义函数
show_args (){
    echo "函数的第一个参数$1"
    echo "函数的第二个参数$2"
    echo "函数的所有参数$@"
    echo '函数中 $0 还是' $0

}
# 调用函数
show_args hello world

[root@kube-master function]# sh func-args.sh
函数的第一个参数hello
函数的第二个参数world
函数的所有参数world
函数中 $0 还是 func-args.sh

4、函数中调用函数

f1(){
  echo "f1...."
}

function f2(){
  f1
  echo "f2..."
}

f2

expect免交互工具

1、安装

yum install -y expect

2、语法结构

spawn   shell 命令程序 

expect   "捕获到shell 命令程序执行之后输出的字符串"  
send  "发送给 shell 命令程序的字符串"
2.1 在命令行中使用
# 在命令行直接输入 expect 可以进入 expect 程序的解释器终端
[root@e5ac44e88027 ~]# expect
expect1.1> spawn echo "hello"   # 发送一条 shell 命令, 这里是指 echo "hello"
spawn echo hello
1490
expect1.2> expect "hello"     # 捕获这个字符串,只要包含这个字符串就可以
hello
expect1.3> send "yes\n"      # 发送一个字符串
expect1.4> expect off           # 结束这次捕获
yes
2.2 在脚本中使用
# 开始 expect  解释器程序
/usr/bin/expect<<EOF

# 设置捕获字符串后,期待回复的超时时间
set timeout 30

spawn   ssh-keygen

# 开始进连续捕获
expect     {
        ".ssh/id_rsa)"       { send    "\n";  exp_continue }
        "Overwrite (y/n)?"   { send    "y\n"; exp_continue }
        "no passphrase):"    { send    "\n";  exp_continue }
        "again:"             { send    "\n";  exp_continue }
}

# 结束 expect 解释器程序
EOF

# ".ssh/id_rsa)" { send "\n"; exp_continue }
# 意思是 捕获到字符串 ".ssh/id_rsa)" 后 发送字符串 "\n" 就是相当于按下回车键
# exp_continue 意思是继续进行捕获,不退出 expect 程序

3、实战案例

# 写个用于自动生成密钥对的函数
auto_keygen (){
    /usr/bin/expect<<EOF

    set timeout 30

    spawn   ssh-keygen

    expect     {

        ".ssh/id_rsa)"       { send    "\n";  exp_continue }
        "Overwrite (y/n)?"   { send    "y\n"; exp_continue }
        "no passphrase):"    { send    "\n";  exp_continue }
        "again:"             { send    "\n";  exp_continue }
    }

EOF
}

# 写个自动免密登录的函数
send_key () {
pwd=upsa
/usr/bin/expect <<EOF
set timeout 30

# 发送公钥给对方服务器
spawn ssh-copy-id root@$1
expect {
"yes/no" { send "yes\n"; exp_continue }
"password:" { send "${pwd}\n"; exp_continue } 
}
expect eof
EOF
}

# 定义一个变量,其值是当前用户的公钥文件
pub_key_file=$HOME/.ssh/id_rsa.pub

# 假如公钥文件不存在,说明需要创建密钥对
if [ ! -f ${pub_key_file} ];then
    auto_keygen
fi

# 循环一个存放 ip 地址的文件,并且把每个 IP地址传递给 函数
for ip in $(cat ./ips.txt)
do
   send_key $ip
done

操作数据库

shell 操作 MySQL 是通过给 mysql 这个客户端程序传递相应的参数实现的
mysql -u用户 -p'password' db_name -e "sql 语句"

#!/bin/bash
HOSTNAME="localhost" #数据库信息
PORT="3306"
USERNAME="root"
PASSWORD="QFedu123!"
DBNAME="d1" #数据库名称
TABLENAME="t1" #数据库中表的名称

exec_mysql="mysql -h${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD}"

#创建数据库
create_db_sql="create database IF NOT EXISTS ${DBNAME}"
${exec_mysql} -e "${create_db_sql}"

${exec_mysql} "show databases;"

#创建表
create_table_sql="create table  IF NOT EXISTS ${TABLENAME} ( name varchar(20), id int(11) default 0 )"
${exec_mysql}   ${DBNAME}   -e   "${create_table_sql}"

#插入数据
insert_sql="insert into  ${TABLENAME}  values('billchen',2)"
${exec_mysql}   ${DBNAME} -e "${insert_sql}"
# 查询
# 查询时候可能需要避免不必要的输出
search_dbs="show databases;"
${exec_mysql}    ${DBNAME}   -e   "${search_dbs}"   -N  -B
# -N 不输出列名(字段名)
# -B 不输出数据之间的边框竖线 (|)
# 输出格式可以是其他的,比如 -H 输出 HTML 格式
# 隐藏用户名和密码
[mysql]
user=root
password='QFedu123!'

mysql  --defaults-file=./mysql_pwd -h 172.17.0.2 -e  "show databases;"  -N -B

正则和grep

怎么说呢?正则这个玩意,必须得会!!

老哥的笔记

1、定义及使用范围

正则表达式基本上是一种“表达式”, 只要工具程序支持这种表达式,那么该工具程序就可以用来作为正则表达式的字串处理之用。 例如 vi , grep, awk,sed 等等工具,因为她们有支持正则表达式, 所以,这些工具就可以使用正则表达式的特殊字符来进行字串的处理。但例如 cp, ls 等指令并未支持正则表达式, 所以就只能使用 Bash 自己本身的通配符而已。

下面用到的模板

cat test.txt

"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
However, this dress is about $ 3183 dollars.
GNU is free air not free beer.
Her hair is very beauty.
I can't finish the test.
Oh! The soup taste good.
motorcycle is cheap than car.
This window is clear.
the symbol '*' is represented as start.
Oh! My god!
The gd software is a library for drafting programs.
You are the best is mean you are the no. 1.
The world <Happy> is the same with "glad".
I like dog.
google is the best tools for search keyword.
goooooogle yes!
go! go! Let's go.
# I am VBird

2、基础

[:alnum:] 代表所有的大小写英文字符和数字 0-9 A—Z a-z
[:alpha:] 代表任意英文大小写字符  A-Z a-z
[:lower:] 代表小写字符       a-z
[:upper:] 代表大写字符        A-Z
[:digit:] 代表数字         0-9

3、入门匹配

^world   匹配以world开头的字符串

# 例子  匹配以#开头的行
grep '^#' test.txt
world$  匹配以world结尾的字符串

# 例子  匹配以!结尾的行
grep '!$' test.txt
.  代表任意的一个字符

# 例子  匹配两个e之间有任意一个字符的行
grep 'e.e' test.txt
\  跳脱字符,将特殊符号的特殊意义去除   # 特殊符号有 '(单引号) " (双引号) .(英文句号)

# 例子  匹配含有单引号'的行
grep \' test.txt

# 例子二 匹配含有英文句号.的行
grep '\.' test.txt
*  代表零到无穷多个 前一个字符  # 因为*为重复前一个字符,所以在*之前必须有一个字符!  
                           #  想要匹配任意字符可以这样    .*  
# 根据下面这个例子可以看出 s* 为一个整体 即*于它前面的字符是一个整体出现在匹配规则中
# 如你想要匹配到 es后面不知道多少s 就必须写 ess*  如果是es* 则会匹配到 单独的e
# 例子 匹配 前面为 es 后面多个s的行
grep 'ess*' test.txt
[list]   字符集合,列出了可选的字符,仅代表包含列表其中一个字符
           # 匹配a[afi]y  就是匹配 aay afy aiy

# 例子  匹配gl 或者gd 
grep 'g[ld]' test.txt
[n1 - n2]  同上,列出的是一个连续的范围 


# 例子  匹配含有数字0-9的行
grep '[0-9]' test.txt
[^list]  反向选择,列表中的是不会出现的字符


# 例子  匹配不含有ood 的行
grep 'oo[^d]' test.txt
\{n,m\}   连续n到m个前面的字符   # 用法同*
# 如果是 \{n\}  是连续n个前面的字符
# 如果是 \{,m\}  是0到m个前面的字符

# 例子  匹配以g开头 d 结尾 中间两个到三个o 的行
 grep 'go\{2,3\}d' test.txt
 
# 例子二  匹配连续两个o 的行
grep 'o\{2\}' test.txt

# 例子三  匹配0到2个连续的o
grep 'o\{,2\}' test.txt


4、扩展正则

支持扩展正则的工具 grep -Eegrepsedawk

grep 如果要支持扩展正则 需要加 -E 或者直接使用egrep

+ 重复一个或一个以上前一个字符 

例子
egrep 'go+d' test.txt
?  零个或一个前面的字符

例子
egrep 'go?d' test.txt
| 或

例子 找出gd 或者 good
egrep 'gd|good' test.txt

() 群组

例子:找到glad 或者 good
egrep 'g(la|oo)d' test.txt 

()+  多个重复群组

例子: 找以A开头 C 结尾 ,中间有一个以上的xyz
egrep 'A(XYZ)+C' test.txt
# 还有一些比较晦涩的东西,自己悟一悟
echo "2019-12-30" |grep -E '[1-9][0-9]{3}-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))'
2019-12-30
echo "1919-12-30" |grep -E '[1-9][0-9]{3}-((0[1-9])|(1[0-2]))-((0[1-9])|([12][0-9])|(3[01]))'
1919-12-30

#第一点 {数字}  可以指定前面东西出现的次数

5、贪婪匹配

grep 默认贪婪

如果想实现非贪婪需要加上-P ,这会使用 Perl 语言环境的正则

贪婪 就是尽可能的多匹配
非贪婪 就是尽可能的少匹配,只需要在一些表示量词(就是次数)的后面加上 ?, 比如: .*? +?

例子

Perl 语言中:

  • \w 表示任意 一个 大小写字母 [a-zA-Z] 、下划线 _ 和数字 [0-9]
  • \d 表示任意 一个 数字 [0-9]
    当然这些规则适用于大部分的 编程语言,比如 python java javascript

awk

一、awk简介

awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。

数据可以来自标准输入、一个或多个文件,或其它命令的输出。

支持用户自定义函数和动态正则表达式等先进功能,是linux/unix
下的一个强大编程工具。

可以在命令行中使用,但更多是作为脚本来使用。

awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。

awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。

gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。

二、awk语法

# 第一种
awk [options] 'commands' filenames

# 第二种
awk [options] -f awk-script-file filenames

# 解释
# options
-F  对于每次处理的内容,可以指定一个子定义的分隔符,默认的分隔符是空白字符(空格或 tab 键 )

# command
BEGIN{} 处理所有内容之前的动作,通常用于定义一些变量,例如 BEGIN{FS=":";OFS="---"}
{}  处理内容中的动作
END{}  处理所有内容之后的动作

# 示例
 awk 'BEGIN{print "----开始处理了---"} {print "ok"} END{print "----都处理完毕---"}' /etc/hosts
----开始处理了---
ok
ok
ok
----都处理完毕---

三、awk工作原理

(1)awk,会处理文件的每一个行,每次处理时,使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束

(2)然后,行被**😗*(默认为空格或制表符)分解成字段(或称为域),每个字段存储在已编号的变量中,从$1开始,
最多达100个字段

(3)awk如何知道用空白字符来分隔字段的呢? 因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空白字符

(4)awk打印字段时,将以内置的方法使用 print 函数打印,awk 在打印出的字段间加上空格。这个空格是内部的一个变量 OFS 输出字段的分隔符, 逗号 , 会和 OFS 进行映射,通过 OFS 可以控制这个输出分隔符的值。

(5)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕

四、记录与字段相关的内部变量

变量作用
$0awk变量 $0 保存当前正在处理的行内容
NR当前正在处理的行是 awk 总共处理的行号。
FNR当前正在处理的行在其文件中的行号。
NF每行被处理时的总字段数
$NF当前处理行的分隔后的最后一个字段的值
FS输入行时的字段分隔符,默认空格
OFS输出字段分隔符,默认是一个 空格
ORS输出记录分隔符, 默认是换行符.

五、格式化输出printf

awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd
awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd
格式含义
%s字符类型
%d十进制整数
%f浮点数类型
%-15s占15字符-表示左对齐,默认右对齐
printf默认不会再行尾自动换行,加\n

六、awk模式和动作

任何 awk 语句都由 模式动作 组成。模式部分 决定动作语句何时触发及触发事件。如果省略模式部分,动作将时刻保持执行状态。

模式可以是任何条件语句或复合语句或正则表达式。

模式可以是

  • 正则表达式

    # 将整行进行正则匹配(包含)
    # 就是当前处理的行有没有包含 指定的模式(书写的正则表达式)  /正则/ 正则需要写在双斜线内
    # 示例
    awk '/^root/' /etc/passwd
    awk '$0 ~ /^root/' /etc/passwd
    awk '!/root/' /tec/ passwd
    awk '$0 !~ /^root/' /etc/passwd
    
    # 将某一字段进行正则匹配
    # 可以使用的匹配操作符(~ 和 !~)  字段 ~ /正则/
    # 示例
    awk -F: '$1 ~ /^alice/' /etc/passwd
    awk -F: '$NF !~ /bash$/' /etc/passwd
    
    # 实现 字符串的完全相等需要使用 ==
    # 字符串需要使用双引号 != 表示不等于
    # 示例
    awk -F: '$NF == "/bin/bash"' /etc/passwd
    awk -F: '$1 == "root"' /etc/passwd
    
    # 比较表达式
    # 比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符,用于比较数字与字符串。
    # 关系运算符有
    # <  小于 例如 x<y
    # <= 小于或等于 x<=y
    # >  大于 x>y
    # >= 大于等于 x>=y
    # == 等于 x==y
    # != 不等于 x!=y
    # 示例
    awk -F: '$3 == 0' /etc/passwd
    awk -F: '$3 < 10' /etc/passwd
    df -P | grep '/' |awk '$4 > 25000'
    
    # 条件表达式
    # 示例
    awk -F: '$3>300 {print $0}' /etc/passwd
    awk -F: '{ if($3>300) print $0 }' /etc/passwd
    awk -F: '{ if($3>300) {print $0} }' /etc/passwd
    awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd
    
    # 算术运算:+, -, *, /, %(模: 取余), ^(幂:2^3)
    # 可以在模式中执行计算,awk都将按浮点数方式执行算术运算
    # 示例
    awk -F: '$3 * 10 > 500' /etc/passwd
    awk -F: '{ if($3*10>500){print $0} }' /etc/passwd
    
    # 逻辑操作符和复合模式
    # && 逻辑与, 相当于 并且
    # ||逻辑或,相当于 或者
    # ! 逻辑非 , 取反
    # 示例
    awk -F: '$1~/root/ && $3<=15' /etc/passwd
    awk -F: '$1~/root/ || $3<=15' /etc/passwd
    awk -F: '!($1~/root/ || $3<=15)' /etc/passwd
    
    # 范围模式, 模式之间用逗号 , 隔开
    # 使用语法是: 起始表达式, 终止表达式
    # 示例 下面的意思是: 从开头是 bin 的行开始匹配成功一直到含有 adm 的行结束匹配,也就是 开头是 bin 的行到含有 adm 的行 的所有内容都符合匹配条件。
    ➜  ~ awk -F: '/^bin/,/adm/ {print $0 }' /etc/passwd
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    
    # 生产实例
    # 统计日志中某个时间范围的 IP 访问量,并进行排序
    # 部分日志
    110.183.58.144 - - [10/May/2018:23:49:27 +0800] "GET http://app.znds/html/20180504/y222sks_2.2.3_dangbei.dangbei HTTP/1.1" 200 14306614 "-" "okhttp/3.4.1"
    1.69.17.127 - - [10/May/2018:23:49:31 +0800] "GET http://app.znds/down/20180205/ttjs_3.0.0.1_dangbei.apk HTTP/1.1" 200 13819375 "-" "okhttp/3.4.1"
    1.69.17.127 - - [10/May/2018:23:49:40 +0800] "GET http://app.znds/down/20180416/ttyj_1.1.6.0_dangbei.apk HTTP/1.1" 200 16597231 "-" "okhttp/3.4.1"
    1.69.17.127 - - [10/May/2018:23:50:00 +0800] "GET http://app.znds/down/20170927/jydp_1.06.00_dangbei.apk HTTP/1.1" 200 36659203 "-" "okhttp/3.4.1"
    # 具体实现
    $ start_dt='10/May/2018:23:47:43
    $ end_dt='10/May/2018:23:49:05'
    $ awk -v st=${start_dt} -v ent=${end_dt} -F'[][ ]' '$5 == st,$5 == ent  {print $1}' app.log  |sort |uniq -c |sort -nr |head -n 10
         66 223.13.142.15
          6 110.183.13.212
          4 1.69.17.127
          1 113.25.94.69
          1 110.183.58.144
          
    # awk正则示例
    # 匹配开头是 bin 的或者开头是 root 的行
    ➜  ~ awk -F: '/^(bin|root)/' /etc/passwd
    root:x:0:0:root:/root:/bin/zsh
    bin:x:1:1:bin:/bin:/sbin/nologin
    
    # 指定多个分割符号
    # 使用[]
    # 示例
    ➜  ~ echo "a b|c d| ||||e | |" |awk -F'[ |]' '{print $10}'
    e
    ➜  ~ echo "a b|c d| ||||e | |" |awk -F'[ |]+' '{print $5}'
    e
    awk -F'[][ ]+' '$4 ~ /^11\/Apr\/2020/, $4 ~ /^17\/Apr\/2020/ && $7 ~ /^\/star\/local\/app/ {j++}END{print "总访问量:"j,"平均:"j/7}' access.log
    
    # 注意: 中括号内的任意字符均视为普通字符, 比如 . * 都被看做是 普通字符。
    # 例如:
    $ echo "a.b*c" |awk -F'[.*]' '{print $1, $2,$3}'
    a b c
    
    

七、awk脚本编程

if语句

# 格式 { if (表达式) {语句; 语句; ...}}
awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
输出: root is administrator.

# 统计系统级别用户的数量
awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd 
输出: 22

if…else语句

# 格式 {if(表达式){语句;语句;...}else{语句;语句;...}}
awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd

awk -F: '{ if($3==0){count++} else{i++} } END{print "管理员个数: "count "系统用户数: "i}' /etc/passwd
输入:
管理员个数: 1系统用户数: 24

awk -F: '{ if($3==0){count++} else{i++} } END{print "管理员个数: "count ; print  "系统用户数: "i}' /etc/passwd
输出:
管理员个数: 1
系统用户数: 24

if…else if…else语句

# 格式
# {if(表达式1) {语句;语句;...} else if (表达式2) {语句;语句;...} else if(表达式3){语句;语句;...} else {语句;语句;...} }
awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd
输出:
1
2
22

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd
输出:
管理员个数: 1
普通用个数: 2
系统用户: 22

八、awk使用外部变量

方法一:awk参数-v(推荐使用,易读)

[root@sharkyun ~]# w=hello
[root@sharkyun ~]# echo "hello world" | awk -v var=$w '$1 == var {print $1}'
hello

方法二:管道符

[root@tianyun ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/cl-root 2.8T 246G 2.5T 9% /
tmpfs 24G 20K 24G 1% /dev/shm
/dev/sda2 1014M 194M 821M 20% /boot

[root@tianyun ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }'
/:9%
/boot:20%

[root@tianyun ~]# i=10
[root@tianyun ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }'
/boot:20%

sed

一、sed工作流程

sed 是一种在线的、非交互式的编辑器,它一次处理一行内容。
处理时,先把当前处理的行内容存储在临时缓冲区中,称为“模式空间”(pattern space),
之后再用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容打印到屏幕。
接着处理下一行,这样不断重复,直到文件末尾。
注意:模式空间的内容和 AWK 中的 $0 是一样的,处理每行的时候,都会被重新赋值为当前行的内容
文件内容并没有改变,除非你使用重定向存储输出。
Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

二、命令格式

# 处理单个文件
sed [options] '[匹配模式] sed 的内部命令' file1

# 处理多个文件
sed [options] '[匹配模式] [sed 的内部命令]' file1  file2

# options 选项是可选的,意思就是没有也行
-r 支持正则
-i 修改
-n 取消默认输出
-e 多重编辑
# 匹配模式 是可选的用于在文件中每一行进行匹配到模式,模式可以是正则,也可以是文件的行号
# 内部的命令也是可选的,没想到吧,但是两个单引号是必须的
s 替换
a 追加
d 删除
i 插入
c 修改
# 注:sed和grep不一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才是非0

三、基础应用

# 支持正则
# 与grep一样,sed在文件中查找模式时也可以使用正则表达式(RE)和各种元字符。正则表达式是括在斜杠间的模式,用于查找和替换,以下是sed支持的元字符。
# 使用基本元字符集 ^, $, ., *, [], [^], \< \>,\(\),\{\}
# 使用扩展元字符集 ?, +, { }, |, ( )
# 使用扩展元字符的方式:
sed   -r
# 在实际使用的时候,都会加上 -r 参数,即使没有用的扩展正则也不会有任何影响。
# 输出内容
# sed 默认会输出文件的每一行,无论这行内容是否能匹配上匹配模式,假如被匹配到的则会再输出一次。
sed   -r   ''     mypasswd
> root:x:0:0:root:/root:/bin/bash
> bin:x:1:1:bin:/bin:/sbin/nologin
> daemon:x:2:2:daemon:/sbin:/sbin/nologin
sed   -r   'p'    mypasswd
> root:x:0:0:root:/root:/bin/bash
> root:x:0:0:root:/root:/bin/bash
> bin:x:1:1:bin:/bin:/sbin/nologin
> bin:x:1:1:bin:/bin:/sbin/nologin
> daemon:x:2:2:daemon:/sbin:/sbin/nologin
> daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 这里的p并不是匹配p字符,而是sed的内部命令,有打印(输出)的作用

# 使用-n 可以屏蔽掉默认输出
sed -rn 'p'   mypasswd
> root:x:0:0:root:/root:/bin/bash
> bin:x:1:1:bin:/bin:/sbin/nologin
> daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 显示包含root的行 
sed -rn '/root/p'  mypasswd
# 匹配root 开头的行
sed -rn '/^root/p'  mypasswd
# 搜索替换
# 搜索每一行,找到有 root 的,把第一个替换为 shark
sed  -r  's/root/shark/'   mypasswd

# 搜索每一行,找到所有的 root 字符,进行全局替换为 `shark`
sed  -r  's/root/shark/g'    mypasswd

# 忽略大小写
sed  -r  's/root/shark/gi'    mypasswd 
# 删除
# 找到含有 root 的进行删除
sed  -r  '/root/d'    mypasswd
# 改变界定符号
# 可以使用不同的 字符 作为界定符号,注意进行转义
sed  -r  '\#root#d'   mypasswd
# 注意:当在模式匹配中使用其他界定符号时,需要对其进行转义。其他界定符用在 s 搜索替换时不必转义。
# 例如:
sed  -r  's#root#shark#'      mypasswd
sed  -r  's%root%shark%'      mypasswd
sed  -r  's|root|shark|'      mypasswd
# 地址(定址)
# 地址用于决定对哪些 行 进行编辑。地址形式可以是数字、正则表达式或二者的结合。如果没有指定地址,sed将处理输入文件中的所有行。
# 全部分删除
sed  -r  'd'        mypasswd

# 第 3 行删除
sed  -r  '3  d'     mypasswd

# 第 1 行到第 3 行都删除
sed  -r  '1,3  d'             mypasswd

# 含有 root 字符串的行删除
sed  -r  '/root/  d'          mypasswd

# 从含有 root 字符串的行开始匹配,一直删除到第 5 行
sed  -r  '/root/,5  d'        mypasswd

# 从含有 halt 的行开始删除,并删除此行之后的 2 行,就是总共删除 3 行
sed  -r  '/halt/,+2  d'      mypasswd

# 含有 root 的行不删除,其他都删除
sed  -r  '/root/ !d'         mypasswd

# 使用行号除以 2 ,余数是 1 的行删除
sed  -r  '1~2  d'             mypasswd

# 使用行号除以 2, 余数 是 0 的 打印出来
sed  -rn  '0~2  p'            mypasswd

# 试试下面这个, 就是 每次处理的行号是被除数,第二个数是除数,第一数是 余数
sed  -rn   '0~3  p'           mypasswd 

四、匹配模式和内部命令

# 替换 s
# //&代表在查找串中匹配到的所有内容,如果没有显示,可以加一个p
sed -rn 's/[0-9][0-9]/&=5/' mypasswd 
# 效果
> operator:x:11:0:operator:/root:/sbin/nologin

> operator:x:11=5:0:operator:/root:/sbin/nologin
# 将前面的no分组,组号为1,然后将nologin替换为no不可登录
sed -r 's/(no)login/\1不可登录/' mypasswd
# 追加 a
sed -r '$a 1.1.1.1 www.qfedu' /etc/hosts

# 如果不加$ 会在每一行的下面追加一次
# 插入 i
# 在第二行后面插入
sed -r '2i\1111111111111' /etc/hosts
# 插入中的换行在插入后也生效
sed -r '2i111111111\
> 2222222222\
> 3333333333' /etc/hosts
# 修改 c
# 将第二行修改为111111111111
sed -r '2c\1111111111111' /etc/hosts

sed -r '2c\111111111111\
> 22222222222\
> 33333333333' /etc/hosts

五、sed常用的操作

# 删除配置文件中 # 号注释的行
sed -ri '/^#/d' file.conf

# 删除开头的一个或者多个空格或者 Tab 键 加上 '#' 或者开头是 '#' 的行
sed -ri '/^[ \t]*#/d' file.conf

# YUM 源修改
sudo sed -ri s/^#baseurl/baseurl/g /etc/yum.repos.d/CentOS-Base.repo
sudo sed -ri s/^mirrorlist/#mirrorlist/g /etc/yum.repos.d/CentOSBase.repo

# 删除配置文件中//号注释行
sed -ri '\#^[ \t]*//#d' file.conf

# 删除无内容空行
# - 开头和结尾之间什么都没有的行
# - 开头和结尾之间有多个空格的行
# - 开头和结尾之间有多个  Tab 键的行
sed -ri '/^[ \t]*$/d' file.conf

# 删除注释行及空行:
# 以下 3 中效果一样,挑一个自己喜欢的
# 使用;分割两个条件
sed -ri '/^[ \t]*#/d; /^[ \t]*$/d' /etc/vsftpd/vsftpd.conf
# 使用| 分割两个条件
sed -ri '/^[ \t]*#|^[ \t]*$/d' /etc/vsftpd/vsftpd.conf
# 使用(|)分割两个条件
sed -ri '/^[ \t]*($|#)/d' /etc/vsftpd/vsftpd.conf

# 修改文件:
sed -ri '$a\chroot_local_user=YES' /etc/vsftpd/vsftpd.conf
sed -ri '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
sed -ri '/UseDNS/cUseDNS no' /etc/ssh/sshd_config
sed -ri '/GSSAPIAuthentication/cGSSAPIAuthentication no' /etc/ssh/sshd_config

# 给文件行添加注释:
sed -r '2,6s/^/#/' a.txt

# 使用小括号进行分组,可以有多个分组, 后面可以使用 \1 获取到第一个分组的内容  
sed -r '2,6s/(.*)/#\1/' a.txt
# &匹配前面查找的内容
sed -r '2,6s/.*/#&/' a.txt 
# 将行首零个或多个#换成一个#
sed -r '3,$ s/^#*/#/' a.txt 

sed -r '30,50s/^[ \t]*#*/#/' /etc/nginx.conf
sed -r '2,8s/^[ \t#]*/#/' /etc/nginx.conf

# sed中使用外部变量
var1=11111
# 无效
sed -r '3a$var1' /etc/hosts
# 正确
sed -r "3a$var1" /etc/hosts
# 有效
sed -r 3a$var1 /etc/hosts
# 报错
sed -r "$a$var1" /etc/hosts
# 有效,但是中间不能有空格
sed -r '$a'"$var1" /etc/hosts
# 有效, 将第一个 $ 进行转义
sed -r "\$a  $var1" /etc/hosts
# 多重编辑选项:-e
sed -e '1,3 d' -e 's/root/shark/' mypasswd
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/shark:/sbin/nologin

# 等同于
sed '1,3 d; s/root/shark/' mypasswd

本文标签: awkShellgrepsed