zoukankan      html  css  js  c++  java
  • shell进阶

    shell 中的高级用法

    1.if

    单重判断

    if cmd; then
        cmd
        cmd
        cmd
    fi
    

    多重判断

    单分支

    if  cmd;then
        cmd
    elif 
        cmd
    fi
    

    双分支

    if cmd; then
        cmd
    elif cmd;then
        cmd
    elif cmd;then
        cmd
    else
        cmd
    fi
    
    

    用于当判断条件的参数

    逻辑判断

    -a && 与
    -o || 或
    ! 非
    =~ 左边变量 ,右边扩展的正则表达式,不能写双引号
    -z 判空
    == 相等
    != 不相等

    大小判断
    -eq //等于
    -ne //不等于
    -gt //大于 (greater )
    -lt //小于 (less)
    -ge //大于等于
    -le //小于等于

    文件比较符
    -e 判断对象是否存在
    -d 判断对象是否存在,并且为目录
    -f 判断对象是否存在,并且为常规文件
    -L 判断对象是否存在,并且为符号链接
    -h 判断对象是否存在,并且为软链接
    -s 判断对象是否存在,并且长度不为0
    -r 判断对象是否存在,并且可读
    -w 判断对象是否存在,并且可写
    -x 判断对象是否存在,并且可执行
    -O 判断对象是否存在,并且属于当前用户
    -G 判断对象是否存在,并且属于当前用户组
    -nt 判断file1是否比file2新 [ ``"/data/file1" -nt ``"/data/file2" ]
    -ot 判断file1是否比file2旧 [ ``"/data/file1" -ot ``"/data/file2" ]

    2.case

    要注意的是case 中使用的是引用变量,而不是声明变量名,$xxx

    case支持glob风格的通配符:
    *: 任意长度任意字符
    ?: 任意单个字符
    []:指定范围内的任意单个字符
    a|b: a或b

    case $num 变量引用 in  
    1|2|3)     判断条件 ,可以使用通配符
        cmd1;
        ;;     根据;;来结束一个case段
    4|5|6)
        cmd2;
        ;;
    *)
        cmd3;
        ;;
    esac
    

    echo $passwd | passwd stdin user 设置用户密码

    3.for

    for 变量名(不是变量引用,不带$) in 列表;do
    循环体
    done

    实例

    for num in {1..10};do
        echo num is $num;
    done
    

    列表生成方式:

    1. 直接给出列表
    2. 整数列表:
      (a) {start..end}
      (b) $(seq [start [step]] end)
    3. 返回列表的命令
      $(COMMAND)
    4. 使用glob,如:*.sh
    5. 变量引用;$@, $*

    列表可以用任意的合集,用命令解析得到的合集也可以,比如填 ls /bin,支持通配符
    {1..100..3} 1到100,每次步进3
    unset sum 删除变量sum,防止影响
    for中使用多行重定向的话 。需要把第一个EOF加- 或者把EOF结尾标志顶格。否则无法识别

    for i in {1..10};do
        cat >>f1<<-EOF
        ASDASD
        ASDASD
        EOF
    done
    

    或者

    for i in {1..10};do
        cat >>f1 <<EOF
        ASDASD
        ASDASD
    EOF
    done
    

    4.for循环的第二种格式语法

    sum=0
    for ((i=1;i<=100;i++))
    let sum+=i
    done

    for i in {1..3};do
    for j in {1..10};do
    if [ (j -eq 5 ];then continue 2;fi echo j=)j
    done
    done
    这边就表示,当j等于5的时候,跳出第二层循环 。不是j循环的第二次,而是第二层!!!就是跳出i循环的当次循环,直接执行i的下次循环

    5.参数移除

    shift n

    shift[n] 参数左移,n可以指定具体数字,表示每次抛弃的参数个数
    比如 1 2 3
    就会先处理完1,然后把1抛弃,处理2,以此类推

    6.并行执行

    并行执行 把所有语句用 {} 包裹,最后加上 & 就是把语句放在后台并行执行。

    wait 脚本执行完成后自动退出,不需要用户按回车

    为什么会输出两次192.168.30.1

    let命令特性点:如果他操作的变量值为 0 返回的是假,
    如果变量非0,返回是真

    比如 i=0
    leti++ ,那么这一次返回的是0

    unset i
    let i++
    echo $? 为 假 1
    unset i
    let ++i
    echo $? 为真 0

    n=10;seq 1 (n 这样用这个, n=10;echo {1..)n} 这样是会报错的,不能这样执行

    n=10;eval echo {1..$n} eval 会扫描并替换变量,然后执行该语句

    用花括号分割变量

    比如 (ix)j ,可能后面的(j会识别成x)j

    写成
    (ix){j} 即可

    openssl rand -base64 20 | tr -dc '[: alpha :]'|head -c8

    $[ 这样的格式里面可以做运算操作 ]

    while 条件;do
    循环体
    done

    : 返回真 等同于 true

    selinux

    用pgrep 查看进程是否存在,然后监控
    pgrep 可以匹配到返回是true(0),而匹配不到会返回false(1)

    向进程发送0信号,可以检测进程是否存在,因为0 信号不会对进程进行任何处理,但是会检查错误。

    until 条件;do
    循环体
    done

    与while相反,条件为假时进入循环,条件为真时,退出

    who |grep USERNAME 查看该用户是否登录

    7.while

    while cmd;do
    cmd
    if cmd;then
    continue 跳过当次执行
    fi
    done

    while cmd;do
    cmd
    if cmd;then
    break 退出当前循环块
    fi
    done

    continue 和 break 后面可以跟数字,用于结束第N层的循环。
    最里面的循环是第一层,往外层递增

    whlie read line;do
    循环体
    done

    while循环的特殊用法(遍历文件的每一行):
    while read line; do
    循环体
    done < /PATH/FROM/SOMEFILE
    依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

    df | while read line;do
    处理df的每一行,支持管道
    done

    8.until 循环

    until cmd;do
        循环体
    done
    

    进入条件:cmd为假
    退出条件:cmd为真
    本质就是一个跟while相反的条件判断

    9.select 创建菜单

    PS3="Please choose the menu 1-4 : " 修改运行脚本时候的select提示符
    select variable in list
    do
    循环体命令
    done

    $REPLAY存储用户手动输入的内容

    自动将List转换为菜单,根据选择的项,给变量赋值

    PS1命令行提示符
    PS2多行重定向提示符
    PS3 select 命令提示符

    select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
    select 经常和 case 联合使用
    与 for 循环类似,可以省略 in list,此时使用位置参量

    下面是一个简单的示例:

    #!/bin/bash
    echo "What is your favourite OS?"
    select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
      break;
    done
    echo "You have selected $var"
    </pre>
    

    该脚本的运行结果如下:

    What is your favourite OS?
        1) Linux
        2) Gnu Hurd
        3) Free BSD
        4) Other
    #? 1
    You have selected Linux</pre>
    

    10.trap 捕获信号

    trap 'echo press ctrl+c' int 捕获Int信号 ,转换为echo press ctrl +c
    trap '' # 捕获信号,并且什么都不做,相当于拦截信号
    trap '-' # 使信号恢复,恢复原信号的操作

    可以捕捉15信号,使程序不可以正常关闭。但是无法捕捉9这个强制关闭的信号

    脚本任务
    alias.sh 配置别名
    vim.sh 配置vim
    yum.sh 配置yum
    pack.sh 安装软件包

    declare -f func4 查询是否存在func4函数

    如果要在脚本里执行rm相关操作,需要检查对应的路径是否正确,变量是否赋值成功

    11.函数

    定义格式
    语法一:

    f_name ()
    {
        ...函数体...
    }
    

    语法二:

    function f_name
    {
        ...函数体...
    } 
    

    语法三:

    function f_name ()
    {
        ...函数体...
    }
    

    函数的优先级比别名高
    函数的生效范围是当前shell
    local 改变变量的有效范围,让他只在该函数内有效

    全局变量 > 普通变量 > local 变量
    declare 声明的变量,也是local 类型的
    declare -ig num=100 加g之后定义,变量就变成了普通变量,不再是local变量
    return 退出函数本身
    在函数中使用echo 输出变量 ,就可以把输出写在if中直接判断
    version (){ echo 1 }
    if [ version -eq 1 ] 判断是成立的
    add() { echo $[$1+$2] }
    add 1 2
    输出3

    函数复用

    把函数保存为bash脚本,

    新的脚本中使用
    source functions (脚本名),相当于引用该脚本

    之后就可以使用该脚本中的函数

    action "commadn successful " 可以显示成功

    action "xxx" /bin/false 表示失败
    action "xxx /bin/true 表示成功

    /etc/init.d/functions 储存了系统内置的函数

    函数可以覆盖定义

    export -f func1 将函数声明为全局函数,让子shell也可以使用该函数,定义函数的时候,不可以使用export

    函数递归调用的时候,只有递归结束的时候,才会执行递归后的操作。

    数组

    关联索引 把数组的索引设置为自定义的格式,而不仅仅是数字

    bash的数组支持稀疏索引(索引不连续),比如0,1, 3 有东西,2 没有 那么数组长度是3 ,但是他们不是连接的。输出2的话是空

    declare -a ARRAY_NAME 普通数组
    declare -A ARRAY_NAME 关联数组 必须先声明再使用

    ${a[1]}

    echo ${name[* ]}
    echo ${name[@]}
    都代表输出数组中的所有元素

    number=({1..10}) 这样也可以定义数组,()中存放任意生成多个字符串的命令都可以。通配符,正则表达式查找,bash命令,都能放

    read -a title a b c 定义数组title ,内容是a b c
    echo a b c | read -a s 定义数组s,内容是a b c (这样是错误的!!管理是不支持交互式赋值的)

    关联数组一定要先定义再使用,否则数组变量会出问题

    关联数组更像一个字典

    ${#name[* ]} 显示name数组的数组长度

    因为使用了管道,所以开启了子shell,导致变量没有值
    这样的话,在循环中使用的数组,声明周期单独只在循环中生效,因为这个时候while read line 使用的是开启的子shell

    字符串处理

    ${var#*word}

    str没有配置 表示变量不存在,没有声明

    生成随机文件名
    mktemp /data/tmpXXXXX 表示有五位的随机字符

    expect

    自动处理交互式命令,需要安装yum 包

    自动传输文件

    !/usr/bin/expect

    spawn scp /etc/fstab 192.168.8.100:/app
    expect {
    "yes/no" { send "yes ";exp_continue }
    "password" { send “magedu " }
    }
    expect eof

    spawn 表示捕获该命令 ,通过expect 来提交信息。当复制命令遇到yes或者no,就自动提交yes,然后继续执行。
    当遇到password ,提交magedu

    /etc/ssh/sshd_config

    GSSAPIAuthentication no 关闭代理 79行
    USEDNS NO 启动 115行

    修改完成后 执行 systemctl sshd restart 重启sshd服务
    加速sshd访问速度

    自动登录

    !/usr/bin/expect

    spawn ssh 192.168.8.100
    expect {
    "yes/no" { send "yes ";exp_continue }
    "password" { send “magedu " }
    }
    interact

    expect eof

    interact 表示开启交互式
    expect eof 结束expect 捕获

    interact 搭配 #expect eof 表示登录终端后,释放对ssh的控制,这样expect就不会再继续捕获命令

    expect 写一个控制脚本
    用bash调用该脚本,做批量机器处理

    矩阵转换

    vim matrix.sh     
         #!/bin/bash
    
        arr=([00]=1 [01]=2 [02]=3 [10]=4 [11]=5 [12]=6 [20]=7 [21]=8 [22]=9)
        size=3
    
        showmatrix () {
        for ((i=0;i<size;i++));do
            for ((j=0;j<size;j++));do
                echo -e "${arr[$i$j]} c"
            done
            echo
    done
    }
    
    echo "Before convert"
    
    showmatrix
    
    for ((i=0;i<size;i++));do
        for ((j=i;j<size;j++));do
            if [ $i -ne $j ];then
                temp=${arr[$i$j]}
                arr[$i$j]=${arr[$j$i]}
                arr[$j$i]=$temp
            fi
        done
    done
    
    echo "After convert"
    
  • 相关阅读:
    CKA&CKAD考试
    进程线程和协程
    HTTP协议
    Centos操作系统启动流程
    高并发下的Linux内核参数优化
    DDoS防护系统建设的一些思路
    DDoS防护实现概述
    Nginx故障排查思路
    git常用指令集
    DNS实现粗粒度容灾
  • 原文地址:https://www.cnblogs.com/ddz-linux/p/10462763.html
Copyright © 2011-2022 走看看