zoukankan      html  css  js  c++  java
  • bash cookbook

    image

    简介

    GNU Bash,又名 Bourne Again Shell。它最初发布于 1989 年,并且轻松成长为 Linux 世界中使用最广泛的 shell,甚至常见于其他一些类 Unix 系统当中。

    shell解析命令行的过程以及eval命令

    变量

    shell中的变量都是全局变量,函数中的变量需要使用 local 将其变成局部变量,防止污染函数外的变量。

    不过从严格意义上,Bash没有变量类型。Bash中的变量,在运行的时候会被展开成其对应的值(字符串)。

    静态变量

    在执行过程中不能改变的变量

    readonly passwd_file=”/etc/passwd”
    readonly group_file=”/etc/group”
    

    变量操作

    1. 大小写切换

    ^大写,,小写, ~大小写切换
    重复一次只匹配一个字母,重复两次则应用于所有字母。

    HI=HellO
    echo "$HI" # HellO
    echo ${HI^} # HellO
    echo ${HI^^} # HELLO
    echo ${HI,} # hellO
    echo ${HI,,} # hello
    echo ${HI~} # hellO
    echo ${HI~~} #hELLo
    
    1. 替换运算符
    ${var:-word}    # 如果var存在且非null,返回它的值;否则返回word
    ${var:=word}    # 如果var存在且非null,返回它的值;否则将word赋值给var,并返回var的值 
    ${var:?word}    # 如果var存在且非null,返回它的值;否则显示var:word
    ${var:+word}    # 如果var存在且非null,返回word;否则返回null
    

    冒号(:)可省略

    1. 模式匹配运算符
    ${var#pattern}    匹配前缀(最小匹配),并返回余下内容
    ${var##pattern}   匹配前缀(最大匹配),并返回余下内容
    ${var%pattern}    匹配结尾(最小匹配),并返回余下内容
    ${var%%pattern}   匹配结尾(最大匹配),并返回余下内容
    

    pattern为正则表达式匹配

    数组

    Bash 提供了一维数组变量。任何变量都可以作为一个数组;内建命令 declare 可以显式地定义数组。数组的大小没有上限,也没有限制在连续对成员引用和赋值时有什么要求。数组以整数为下标,从 0 开始。

    1. 定义和初始化数组
    declare -a array            # 显示声明了数组array
    array[key]=value            # array[0]=one
    array=(value1 value2...)    # value的形式都是[subscript]=string,下标和等号可以省略,示例如下。
    array=([0]=value1 [2]=value3 [3]=value[4])
    
    # 关联数组的另一种定义方式
    mydict=(["name"]=guess ["old"]=18 ["favourite"]=coconut ["my description"]="I am a student")
    

    从上面来看数组的定义也是非常灵活多变的,能够满足我们大部分的需求,跟其其它语言最大的区别就是shell中的数组大小没有上限,也可以理解为数组是动态的。

    1. 数组的访问
      数组的任何元素都可以用${array[subscript]}来引用,花括号是必须的,以避免和路径扩展冲突。
      如果 subscript 是@或是*,它扩展为array的所有成员。

    这两种下标只有在双引号中才不同。在双引号中,"${name[*]}"扩展为一个词,由所有数组成员的值组成,用特殊变量IFS的第一个字符分隔数组成员;"${array[@]}"将array的每个成员扩展为一个词。 如果数组没有成员,${name[@]} 扩展为空串。

    示例--"${name[*]}""${array[@]}"的不同

    #!/bin/bash
    
    arr=("one" "two")
    for i in "${arr[*]}"
    do
        echo ${i}
    done
    
    for i in "${arr[@]}"
    do
        echo ${i}
    done
    

    输出如下

    one two
    
    one
    two
    
    1. 数组的删除
      用unset来进行数组的删除
    unset array[2] # 删除第三个成员
    unset array    # 删除整个数组
    
    1. 数组的长度
    ${#arr[@]}
    ${#arr[*]}
    ${#arr}    #错误的。这个获取的是数组第一个成员的长度。
    
    1. 数组的”切片”操作
      获取数组的“子串“用${arr[@]:n:m}来表示,如果没有:m那么就获取从下标n开始到最后一个元素的“字串“,示例如下:
    #!/bin/bash
    
    arr=(one two three four)
    
    echo ${arr[@]:2}
    echo ${arr[@]:1:3}
    echo ${arr[@]:0}
    

    输出如下

    three four
    two three four
    one two three four
    
    1. 关联数组
      shell中还可以声明一个关联数组,普通数组只能使用整数作为数组的索引,而关联数组则使用字符串作为数组的索引。这个关联数组有点像其它语言中的字典。在mac下的bash 中的declare不含这个-A这个参数。
    #!/bin/bash
    
    declare -A array
    
    array["age"]=29
    array["name"]=Yang
    
    # 输出数组的value
    echo "${array[@]}"
    
    # 遍历数组的值
    for a in "${array[@]}"; do
            echo "${a}"
    done
    
    # 通过下标获取元素值
    echo "${array[age]}"
    
    # 输出数组的key
    echo "${!array[@]}"
    
    # 遍历数组的key
    for a in "${!array[@]}"; do
            echo "${a}"
    done
    

    输出

    Yang 29
    Yang
    29
    29
    name age
    name
    

    应用

    1. 判断一个指定的字符串是否在该数组中

      if echo "${ARR[@]}" | grep -w "item_1" &>/dev/null; then
      	echo "Found"
      fi
      

    判断某个元素是否在数组内的几种方法

    四则运算

    1. bash支持的算数运算
    +	 - 	* 	/
    

    有些场景中,乘法符号需要转义

    1. 算数运算实现方式
    let a=a+b			  计算结果无法直接获取,需要赋值后才能使用
    var=$[算数表达式]		计算结果可以直接使用,建议使用
    var=$((算数表达式))	同上
    var=$(expr arg1 arg2 arg3)
    
    1. 浮点数计算

    使用shell内置命令bc

    # 进制转换
    echo "obase=2; ibase=2; 1+1" | bc
    
    # 保留精度
    echo "scale=2;1/2" | bc
    
    # 多行计算
    # v1=$(bc << EOF
    > v2=1
    > v3=2
    > v2+v3
    > EOF
    > )
    # echo $v1
    3
    
    1. 增强型赋值
    += 	-=	 *= 	/= 	%=
    
    let var=var1+=1
    let var++	# 自增
    let var--	# 自减
    

    条件测试

    分类

    • 整数测试
    • 文件测试
    • 字符测试

    真返回值为true或者false

    条件比较测试表达式有以下三种

    [ expression ]
    [[ expression ]]
    test expression
    

    整数测试

    -eq:=
    -ne:!=
    -gt:>
    -lt:<
    -ge:>=
    -le:<=
    

    文件测试

    1. 存在性测试
    -e file	是否存在
    -f file	是否为普通文件
    -d file	是否为目录
    
    1. 权限测试
    -r file	指定文件对当前用户是否可读
    -w file	指定文件对当前用户是否可写
    -x file	指定文件对当前用户是否可执行
    -u file	当前用户是否是文件的属主
    -g file	当前用户是否是文件的属组
    
    1. 文件大小测试
    -s file	文件存在且非空
    

    字符测试

    [[ ]]或者[ ]都可以

    1. 等值比较

    =或者==注意:等号两端要有空格

    1. 不等比较

    !=注意:等号两端要有空格

    1. 是否为空测试
    -z string:测试字符串是否为空,空为真;
    -n string:测试字符串是否不为空,不空为真;
    ~= 左侧的字符串能否被右侧的PATTERN所匹配
    

    组合条件测试

    主要分两类

    COMMAND1 && COMMAND2
    COMMAND1 || COMMAND2
    ! COMMAND1
    
    [ EXPRESSION1 -a EXPRESSION2 ]
    [ EXPRESSION1 -o EXPRESSION2 ]
    [ ! EXPRESSION1 ]
    

    示例,传递一个用户名参数给脚本,判断此用户的用户名跟其基本组的组名是否一致,并将结果显示出来。

    #!/bin/bash
    if [ $# -ne 1 ]; then
        echo "Please enter a argument."
        exit 1
    elif ! id $1 &> /dev/null; then
        echo "No such user."
        exit 2
    elif [ $1 == $(id $1 -g -n) ]; then
        echo "Same."
    else
        echo "Diffrent."
    fi
    

    选择语句

    case SWITCH in
    value1)
        statement1
        ...
        ;;
    value2)
        statement2
        ...
        ;;
    *)
        statement3
        ...
        ;;
    esac
    

    循环语句

    循环需要有进入条件和退出条件

    for--有限循环

    # 形式1
    for 变量 in 列表;do
        循环体
    done
    
    # 形式2
    for (( expr1 ; expr2 ; expr3 )); do 
      循环体
    done
    

    生成整数列表

    {1..100}
    `seq [起始数] [步进长度] 结束数`
    

    示例

    for i in `seq 1 $a`; do echo $i; done
    

    while--无线循环

    条件满足则执行循环

    while CONDITION; do
      循环体
    done
    

    示例

    while的特殊用法一,死循环

    while :; do
    	循环体
    done
    

    while的特殊用法二,按行读取文件

    while read LINE; do
    	循环体
    done < /PATH/TO/SOMEFILE
    

    until

    满足条件则结束循环

    until CONDITION; do
      循环体
    done
    

    continue

    提前结束本轮循环,进入下一轮循环

    函数

    • 通过位置传递参数
    • 通过 echo 返回值
    • 通过return 返回状态码
    1. 定义

      function func_name(){
          ...函数体...
      }
      
    2. 直接通过函数名调用,函数名后不用加括号。

    格式化输出 echo printf

    echo

    -n 不换行输出
    -e 支持扩展
    

    printf

    使用printf可以输出更规则更格式化的结果。它引用于C语言的printf命令,但是有些许区别。
    printf可以指定字符串的宽度、实现左对齐(使用减符号-)、右对齐(默认的)、格式化小数输出等。

    使用printf最需要注意的两点是:

    • printf默认不在结尾加换行符,它不像echo一样,所以要手动加“ ”换号;
    • printf只是格式化输出,不会改变任何结果,所以在格式化浮点数的输出时,浮点数结果是不变的,仅仅只是改变了显示的结果。
    > printf "%-5s %-10s %-4s
    " No Name Mark     # 三个%分别对应后面的三个参数
    > printf "%-5s %-10s %-4.2f
    " 1 Sarath 80.34 # 减号“-”表示左对齐
    > printf "%-5s %-10s %-4.2f
    " 2 James 90.998 # 5s表示第一个参数占用5个字符
    > printf "%-5s %-10s %-4.2f
    " 3 Jeff 77.564
    

    其他

    位置参数 $@ $* $#

    $* 表示从1开始所有位置的参数,如果扩展发生在双引号内,即"$*",则扩展包含每个参数值的单词,每个参数值用特殊表量IFS的第一个字符分割;也就是说,"$*"等价于"$1c$2c...",其中,c时特殊变量IFS的第一个字符。如果变量IFS没有定义,则参数之间默认用空格分割。

    $@也扩展为从1开始的所有位置参数。但当它的扩展发生在双引号内时,每个参数都扩展为分割的单词。即:"$@"等价于"$1"、"$2" ...。参数@与*之间的区别会在for循环中体现出来。循环时用 $@

    如果命令运行失败让脚本退出执行

    set -o errexit
    set -e
    

    若有用未设置的变量即让脚本退出执行

    set -o nounset 
    set -u
    

    BASH中用 read 实现“按任意键继续”

    read -s -n1 -p "按任意键继续 ... "
    

    参数说明
    -s 指输入的字符屏幕上不可件,应该说可见,但由于和终端的背景色相同,故不可见
    -n 1 表示仅接收1个字符,按回车键也属于一个字符
    -p 是指提示符

  • 相关阅读:
    atitit.ntfs ext 文件系统新特性对比
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.图片木马的原理与防范 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.jdk java8的语法特性详解 attilax 总结
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit.远程接口 监控与木马   常用的api 标准化v2 q216
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结
    Atitit.跨平台预定义函数 魔术方法 魔术函数 钩子函数 api兼容性草案 v2 q216  java c# php js.docx
  • 原文地址:https://www.cnblogs.com/hiyang/p/12611836.html
Copyright © 2011-2022 走看看