目录

Bash语法讲解

变量操作

变量声明(非必须操作)

  1. 首个字符必须为字母(a-z,A-Z)
  2. 中间不能有空格,可以使用下划线_
  3. 不能使用标点符号
  4. 不能使用bash里的关键字(help查看保留关键字)
  1. 在赋值等号 “=” 的两边没有空格,任何空格将导致错误
  2. 单双引号,注意具体场合
  • declare -a 声明一个数组
  • declare -i 声明一个整型
  • declare -x 声明为环境变量
  • declare -r 声明一个只读变量

可变变量

如: a=1 b=“hello”

只读变量

readonly a=“nochange”

内置变量

变量名含义
$0脚本名字
$1~$9带入参数的位置
${10}第10个位置的参数
$#带入参数的个数
$*所有的位置参数(作为单个字符串) *
$@所有的位置参数(每个都作为独立的字符串)
$?返回值
$$脚本的进程ID(PID)
$_之前命令的最后一个参数
$!运行在后台的最后一个作业的进程ID(PID)

数据数组

names="I like python"
names=(hello world python)
 
if [[ "${names[@]}"  =~ "python" ]]; then
    echo '字符串存在'
fi
添加数据元素
array=()
array+=("first")
echo ${array[@]}

随机数组键值

IPS=(192.168.12.11 192.168.12.12 192.168.12.13 192.168.12.14)
 
key=$(( $RANDOM % ${#IPS[*]} ))
value=${IPS[$key]}
 
echo $key $value

数据字典

redisService=([1020]=marco [1021]=shanks [1022]=yupoo [1023]=updns [1024]=robin)
echo ${#redisService[*]}
 
for port in ${!redisService[*]};do
   name=${redisService[$port]}
   echo $name, $port
done

变量初始化

表达式含义
${var}变量var的值, 与$var相同
${var-DEFAULT}如果var没有被声明, 那么就以$DEFAULT作为其值
${var:=DEFAULT}如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值
${var:?ERROR}如果var没被设置, 那么就打印$ERROR
${!varprefix*}匹配之前所有以varprefix开头进行声明的变量

字符串变量操作

表达式含义
${#string}$string的长度
${string:position}在$string中, 从位置$position开始提取子串
${string:position:length}在$string中, 从位置$position开始提取长度为$length的子串
${string#substring}从变量$string的开头, 删除最短匹配$substring的子串
${string##substring}从变量$string的开头, 删除最长匹配$substring的子串
${string%substring}从变量$string的结尾, 删除最短匹配$substring的子串
${string%%substring}从变量$string的结尾, 删除最长匹配$substring的子串
${string/substring/replacement} 使用$replacement, 来代替第一个匹配的$substring字符串
${string\/\/substring/replacement} 使用$replacement, 代替所有匹配的$substring字符串
${string/#substring/replacement} 如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring字符串
${string/%substring/replacement} 如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring字符串

条件判断

文件类

标记代表含义
-e filename 如果 filename 存在,则为真
-b filename 如果 filename 存在,并且是块文件,则为真
-c filename 如果 filename 存在,并且是字符文件,则为真
-d filename 如果 filename 存在,并且为目录,则为真
-f filename 如果 filename 存在,并且为常规文件,则为真
-h filename 如果 filename 存在,并且为符号连接,则为真
-s filename 如果 filename 存在,并且大小不为零,为真
-u filename 如果 filename 存在,并且为set-user-id,为真
-g filename 如果 filename 存在,并且为set-group-id,为真
-r filename 如果 filename 存在,并且可读,则为真
-w filename 如果 filename 存在,并且可写,则为真
-x filename 如果 filename 存在,并且可执行,则为真
-k filename 如果 filename 存在,并且设置了sticky位,为真
-p filename 如果 filename 存在,并且为有名管道(FIFO),真
-o optname 如果 shell 选项 optname 被开启,则为真
-t fd 如果文件描述符被打开并指向一个终端,则为真
-O filename 如果 filename 存在,并且被有效用户ID所拥有,则为真
-G filename 如果 filename 存在,并且被有效组ID所拥有,则为真
-S filename 如果 filename 存在,并且为一个socket,则为真
-N filename 如果 filename 存在,并且在上次读取后被修改过,则为真
file1 -nt file2如果 file1 比 file2 新,或者 file1 存在 file2 不存在,则为真
file1 -ot file2如果 file1 比 file2 旧,或者 file2 存在 file1 不存在,则为真
file1 -ef file2如果 file1 和 file2 都指向同样的设备(device)和索引节点号(inode numbers),则为真

数值类

标记代表含义
-eq 等于 [ $num1 -eq $num2 ]
-ne 不等于 [ 100 -ne $num1 ]
-lt 小于 [ 100 -lt expr $num1 + $num2 ]
-le 小于或等于 [ 100 -le expr $num1 \* $num2 ]
-gt 大于 [ 100 -gt expr $num1 / $num2 ]
-ge 大于或等于 [ 100 -ge expr $num1 % $num2 ]

字符类

标记代表含义
-z string如果 string 空为真
-n string如果 string 长度不为零为真
string1 != string2如果 string1 与 string2 不同,则为真
string1 == string2如果 string1 与 string2 相同,则为真
string1 > string2如果 string1 按字典顺序比较大于 string2,则为真
string1 \< string2如果 string1 按字典顺序比较小于 string2,则为真

流程控制

如: if while for

分支

if…then…fi
if…then…else..fi
if…then…elif…then…else…fi
case…in…esac

表达式分支判断

score="90"
 
if [ $score -ge 90 ];then
        echo "A"
elif [ $score -ge 80 ];then
        echo "B"
elif [ $score -ge 70 ];then
        echo "C"
else
        echo "D"
fi

字符匹配判断

case "$1" in
        start)
                echo "start server...";;
        stop)
                echo "stop server...";;
        *)
                echo "unknown action";;
esac

循环

for …in …do…done
while …do…done
while read…do…done

for循环版本

total=0
 
#for((i=0;i<=100;i++));do
for i in `seq 1 100`;do
        ((total+=i))
done
 
echo $total

while循环版本

total=0
i=0
while [ $i -le 100 ];do
        total=$[$total+$i]
        ((i++))
done
 
echo $total

while循环读取参数

#!/bin/sh
verbose=''
 
while getopts 'af:v' flag; do
    case "${flag}" in
        a) echo "aaa";;
        f) files="${OPTARG}" ;;
        v) verbose='1.0.0' ;;
        *) echo "Unexpected option ${flag}" ;;
    esac
done
[ ! -z $files ] && echo $files
[ ! -z $verbose ] && echo $verbose

注意:如果字符后跟冒号(例如f:),则该选项预期具有参数。

用法示例:./script -v -a -b -f filename

while读取文件行

#!/bin/sh
while read -r LINE;do
       echo $LINE
done < test.txt

菜单

MENU="TV Movie Game Sport"
echo "which do you like?"
select list in $MENU Quit;do
        [ $list = "Quit" ] && echo "ByeBye" && break;
        echo "Oh,you like $list !"
done

内置函数

命令含义
. file or source filedot命令从文件file中读取命令并执行
:空操作,返回退出状态0
alias显示和创建已有命令的别名
bg把作业放到后台
bind显示当前关键字与函数的绑定情况,或将关键字与readline函数或宏进行绑定
break从最内层循环跳出
cd [arg]改变目录,如果不带参数,则回到主目录,带参数则切换到参数所指的目录
declare [var]显示所有变量,或用可选属性声明变量
dirs显示当前记录的目录(pushd的结果)
echo [args]通用打印
prinf格式化输出
eval [args]把args读入Shell,并执行产生的命令
exec command运行命令,替换掉当前Shell
exit [n]以状态n退出Shell
export [var]使变量可被子Shell识别
fc历史的修改命令,用于编辑历史命令
fg把后台作业放到前台
getopts解析并处理命令行选项
history显示带行号的命令历史列表
jobs显示放到后台的作业
kill [-signal process]向由PID号或作业号指定的进程发送信号。输入kill-l查看信号列表
let用来计算算术表达式的值,并把算术运算的结果赋给变量
local用在函数中,把变量的作用域限制在函数内部
logout退出登录Shell
popd从目录栈中删除项
pushd向目录栈中增加项
pwd打印出当前的工作目录
read [var]从标准输入读取一行,保存到变量var中
readonly [var]将变量var设为只读,不允许重置该变量
return [n]从函数中退出,n是指定给return命令的退出状态值
set设置选项和位置参量
shift [n]将位置参量左移n次
stop pid暂停第pid号进程的运行
suspend终止当前Shell的运行(对登录Shell无效)
test检查文件类型,并计算条件表达式
times显示由当前Shell启动的进程运行所累计用户时间和系统时间
trap [arg] [n]当Shell收到信号n(n为0、1、2或15)时,执行arg
ulimit显示或设置进程可用资源的最大限额
umask [八进制数字]用户文件关于属主、属组和其他用户的创建模式掩码
unalias取消所有的命令别名设置
unset [name]取消指定变量的值或函数的定义
wait [pid#n]等待pid号为n的后台进程结束,并报告它的结束状态

read 命令

#!/bin/sh
read -t15 -n5 -p "请输入你的编号(<=5位数)" userid
read -t5  -n5 -s -p "请输入你的密码(限时5秒)"  userpass
 
printf "\n%10s : %10s\n" $userid $userpass
#!/bin/bash 
read -n1 -p "Do you want to continue [Y/N]? " answer 
case $answer in 
Y|y) 
    echo "fine ,continue";; 
N|n) 
    echo "ok,good bye";; 
*) 
    echo "error choice";; 
esac
exit 0
#!/bin/sh
BONDING="bond0|eth0@eth1@eth2@eth3@eth4@eth5|0|118.123.118.134|255.255.255.224|118.123.118.129|1500"
xx=$IFS;IFS="|";read -r nick devs mode ip mask gw mtu <<<"$BONDING";IFS=$xx

printf 命令

#!/bin/bash
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876

Bash命令行小技巧

ctrl-a 跳转到行首 
ctrl-e 跳转到行尾 
ctrl-b 往后移动字符
ctrl-f  往前移动字符
ctrl-w 回退剪切一个单词 
ctrl-u 剪切至行首  
ctrl-k 剪切至行尾 
ctrl-y 粘贴剪切板内容 
ctrl-r 反向搜索历史命令 

Bash的颜色方案

下表是linux终端所支持的基本颜色的代码:

前景背景颜色
3040黑色
3141红色
3242绿色
3343黄色
3444蓝色
3545紫红色
3646青蓝色
3747白色

除了基本的色彩代码,linux还支持一些额外的样式控制代码,如下表所示:

代码含义
0OFF
1高亮显示
4下划线
5闪烁
7反白显示
8不可见

演示代码

#/bin/bash
for STYLE in 0 1 4 5 7 8; do
    for FG in 30 31 32 33 34 35 36 37; do
        for BG in 40 41 42 43 44 45 46 47; do
            CTRL="\033[${STYLE};${FG};${BG}m"
            echo -en "${CTRL}"
            echo -n "${STYLE};${FG};${BG}"
            echo -en "\033[0m"
        done
        echo
    done
    echo
done
# Reset
 
echo -e "\033[0m"