shell practices

Table of Contents

1 简介

基于 bash shell 讲解。

2 基础语法

3 变量类型

3.1 数字

3.1.1 整数

3.1.2 浮点数

  • bash 中只能处理整数。
  • 变量赋值时候等号两边不能有空格。

3.2 字符串

3.2.1 赋值

3.2.2 拼接

直接

3.2.3 截取

使用${expression}方法:

  • ${string:-word}
  • ${string:=word}
  • ${string:?word}
  • ${string:+word}
  • ${#string}

    获得字符串的长度。

  • ${string%regx}

    用途是从右边开始删除第一次出现子字符串即其右边字符,保留左边字符。用法为 %substr*, 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str%/*}
    
  • ${string%%regx}

    用途是从右边开始删除最后一次出现子字符串即其右边字符,保留左边字符。用法为 %%substr*, 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str%%/*}
    
  • ${string#regx}

    用途是从左边开始删除第一次出现子字符串即其左边字符,保留右边字符。用法为 #*substr, 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str#*//}
    
  • ${string##regx}

    用途是从左边开始删除最后一次出现子字符串即其左边字符,保留右边字符。用法为 ##*substr, 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str##*/}
    
  • ${string:start:len}

    从左边第几个字符开始以及字符的个数,用法为: start:len, 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str:0:5}
    echo ${str:7}
    
  • ${string:0-start:len}

    从右边第几个字符开始以及字符的个数,用法: , 例如:

    str='http://www. 你的域名. com/cut-string.html'
    echo ${str:0-6:10}
    

3.2.4 替换

3.2.5 匹配

3.3 数组

3.3.1 定义赋值

  • 使用[]操作符

    names[0]='zhao'
    names[1]='li'
    
  • 使用()直接赋值

    names=('zhao' 'li')
    
  • 使用 declare -a 定义数组。这种方法可以将一个空的变量定义成数组类型

    declare -a name
    
  • 从文件中读取数组

    # 将每一行读取为数组的一个元素
    names=(`cat 'names.txt'`)
    
  • 使用 read -a 来拆分字符串构造数组

    PROVERB="All work and no play makes Jack a dull boy."
    read -a WORDS <<< $PROVERB
    echo "$WORDS"
    echo "${#WORDS}"
    echo "${WORDS[*]}"
    echo "${WORDS[@]}"
    echo "${#WORDS[*]}"
    echo "${#WORDS[@]}"
    
  • 用指定分隔符来拆分字符串构造数组

    前面的例子中要分割的字符串是以空格分割的,现在举一个以: 分割的例子。如果分隔符不是空白,而是别的,那么需要借助 IFS 变量。

    echo $IFS
    IFS=: read -r -a DIRS <<< "$PATH"
    echo $IFS
    declare -p DIRS
    
  • 使用 cut 命令分隔字符串

    echo "$STR" | cut -f $N
    # 以 TAB 分隔,打印第 N 个子串值,N 从 1 开始计数。
    
    echo "$STR" | cut -d "$DELIM" -d $N
    # 以指定 DELIM 分隔,打印第 N 个子串值,N 从 1 开始计数。其中,-d 部分也可以是 $N1,$N2,$N3 的形式,即输出多个子串。
    
  • 使用 awk 命令分隔字符串

    echo "$STR" | awk '{print $1}'
    

3.3.2 拼接数组

通过字符和数组的相互转换完成拼接工作。

adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
adobe2=('Fireworks' 'Illustrator')
adobe3=(${adobe[@]} ${adobe2[@]})
echo ${#adobe3[@]}

3.3.3 删除元素

  • 使用命令替换并重新赋值的方式删除数组元素。
# 删除 Photoshop 元素
adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
adobe=(${adobe[@]:0:2} ${adobe[@]:3})
echo ${adobe[@]}
  • 使用正则表达式替换
adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
adobe=(${adobe[@]/Photoshop/})
echo ${adobe[@]}

3.3.4 截取

命令替换对数组也是有效的,可以使用偏移操作符来取得数组的一部分:

adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
echo ${adobe[@]:1:3}

3.3.5 替换

可以借助数组和字符串的转换以及字符串替换功能来完成。

adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
echo ${adobe[@]/Flash/FlashCS5}
# 将替换后的值重新保存成数组
adobe=(${adobe[@]/Flash/FlashCS5})

3.3.6 长度

使用 “@” 这个特殊的下标,可以将数组扩展成列表,然后就可以使用 bash 中的获取变量长度的操作符 “#” 来获取数组中元素的个数了:

adobe=('Flash' 'Flex' 'Photoshop')
echo ${#adobe[@]}

有趣的是,没有定义的数组下标,并不会占用数组中元素的个数:

adobe=([0]='Flash' [2]='Flex' [4]='Photoshop')
echo ${#adobe[@]}

3.3.7 遍历

使用 for in 循环读取数组:(其实还是借助字符串列表)

adobe=('Flash' 'Flex' 'Photoshop' 'Dreamweaver' 'Premiere')
for item in ${adobe[@]};do
    echo $item
done

4 运算符

5 作用域

6 结构化命令

6.1 if

6.1.1 if-then

if command
then
    command
fi

bash shell 的 if 语句会运行 if 行定义的那个命令。如果该命令的退出状态码是 0(该命令)成功执行,位于 then 部分的命令就会被执行。

6.1.2 if-then-else

if command
then
    commands
else
    commands
fi

6.1.3 嵌套 if

if command1
then
    commands
elif command2
then
    commands
fi

6.1.4 test 命令

通过 test 命令测试和命令的退出码无关的条件。判断条件中的[]只是 test 命令的语法糖,注意左括号右侧和右括号左侧都要各加一个空格符。

  • 数值比较:-eq -ge -gt -le -lt -ne,注意,bash 只能处理整数的比较。
  • 字符串比较:
    • 相等性:= !=
    • 字符串顺序:< >
      • 注意大小符号必须转义:

          str1=baseball
          str2=hockey
        
          if [str1 \< str2]
          then
              echo "str1 < str2"
          fi
        
      • 大于小于顺序和 sort 命令所采用的不同,主要表现在大写字母的处理上。test 命令中大写字母会被当成小于小写字母;而 sort 命令排序时,小写字母会先出现。
    • 字符串大小:-n -z
  • 文件比较:-d -e -f -r -s -w -x -O -G -nt -ot

6.1.5 复合条件测试

使用 || 或 && 测试。

6.1.6 if-then 高级特性

疑问:这两种方式判断返回值是 true 而不是 0,为何?

双圆括号内使用高级表达式
双方括号内操作字符串

除了 test 命令支持的字符串比较方法,还可使用正则表达式匹配。

6.2 case

case variable in
    pattern1 | pattern2) commands1;;
    pattern3) commands2;;
    *) default commands;;
esac

注意 pattern 后面的右圆括号,以及命令后面的两个分号。

6.3 for

for var in list
do
    commands
done

该命令遍历列表中的值。那么如何产生列表中的值?

  • 本身 list 就是列表。
  • 变量作为列表。
  • 命令输出作为列表。 使用内部字段分隔符(IFS)分隔列表中的字段。例如指定回车为字段分隔符:

    IFS=$'\n'
    

    还可以指定多个 IFS 字符:

    IFS=$:;
    
  • 使用通配符遍历目录。
  • bash shell 中还可以使用 C 语言风格的 for 命令,注意括号内侧两边不是必须有空格。

    for(( i=1; i<10; ++i))
    do
        echo $i
    done
    

6.4 while

while command
do
    other commands
done

6.5 util

until command
do
    other commands
done

6.6 break

可以使用 break n 来指定跳出循环的层次。

6.7 continue

6.8 处理循环输出

可以在 done 后面添加命令处理循环的输出。

7 并行处理

8 重定向

  • 注意内联重定向的使用。

9 管道

  • 不要以为管道链接会一个一个运行命令。Linux 系统实际上会同时运行这两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会立即送到第二个命令。传输数据不会用到任何中间文件或缓冲区域。

10 用户输入

10.1 命令行参数

  • 可以使用位置参数($0….${10}….)读取命令行的参数。

10.2 特殊参数

  • \(#表示命令行参数个数,但获取最后一个参数应该写作\){!#}。
  • $*会将命令行上的所有参数当作单个单词保存。
  • $@将命令行上的所有参数当作同一字符串中的多个独立的单词。

10.3 移动变量

  • shift 命令用来移动参数。

10.4 处理选项

10.5 选项标准化

10.6 获得用户输入

  • 使用 read 命令获取用户输入,-p 选项指定提示符。-t 指定超时时间。-s 用来输入密码。

11 呈现数据

  • 重定向错误和数据:1> 2> 以及&>

12 控制脚本

12.1 定时运行作业

  • at
  • cron

13 数据库

13.1 访问 mysql 并返回结果

  • 返回单行结果

    read tips_type url <<EOF
     $(mysql -u root -ptoor -D tips_server -Bse "select tips_type,url from tips where tips_type='bubble';")
    EOF
    echo -e "$tips_type \t $url \n"
    
  • 返回结果集
while read -a row
do
    echo ${row[0]} ${row[1]}
done <<EOF
 $(mysql -u root -ptoor -D tips_server -Bse "select tips_type,url from tips;")
EOF

14 函数

14.1 eval

可以进行变量嵌套。

Author: lsl

Created: 2016-08-07 Sun 19:48

Validate