Bash语言总结

循环语法妙用

输出读取文件的的每一行

while read line  && [[ $word != end ]];do
    echo $line
done < /path/file;

for循环可以用{}代替do,done,类似C语法的形式

#!/bin/bash
for i in seq 10
{
    echo $i
}

此外还可以通过while 与 read命令获取,PIPE管道的标准输入

#!/bin/bash
while read line;do
    echo $line
done  ##示例: ls | ./test.sh

test命令

test命令基本等价于 []
用法示例:

if test -e ./file;then
   echo true
fi

表达式相关

获取表达式的值 : $(())
示例:

echo $((6%3))
输出   0

也可以进行赋值

$((var=6%3))
echo $var
输出var的值

数组相关

数组定义

arr=(`ls ./`)
arr=(1 2 3 4)

数组遍历

arr=(1 2 3 4)
for i in ${arr[*]};do
    echo $i
done

数组的截取

arr=( one two three four five five )
echo ${arr[@]:1:3} #1是数组要截取的起始位置,3是截取数组的长度
echo ${arr[@]#f*r} #删除匹配到的f*r  懒惰模式
echo ${arr[@]##t*e} #删除匹配到的t*e 贪婪模式

unset arr[3] #删除指定的元素

其它的截取、替换、删除不在赘述,详情参照字符串,使用方法与字符串类似,只是作用的元素不一样。

if条件判断的注意事项

[]变量与[或者]需要空格隔开
test命令与[]的执行可以说基本一致,只是执行的方法
[[]]遵循逻辑短路,[]不遵循逻辑短路
[[]]支持 && || > < 逻辑判断符
-a, -o 表示逻辑
提示:
[]中只能使用-a或者-o进行与逻辑判断,[[]]支持&&操作符
[]或者[[]]中使用问题:
1.判断条件值需要用空格与[隔开
2.判断条件需要两个值需要与逻辑判断符用空格隔开123 == 123,否则会一直返回true
3.if判断的用法不仅限于 [[]] 判断

if echo "$word" | grep "123"
then
echo "123"
else
echo "not found"
fi

另一种方式的if else,这种方式使代码更加简洁,但是多条命令还是推荐之前的写法

#!/bin/bash
a=abc
b=efg
c=jlk
[[ -z $c ]] && echo $b || echo $a #输出abc 返回false

case条件判断

case条件判断中,无需break,跳出默认不会贯穿执行

case $a in 
a|A)
    echo "A|a"
;;
b|B)
    echo "B|b"
;;
esac

字符串

实现字符串的拼接
1.str= str1 {str2}
2.str=” str1 str2”

注意以下涉及位置的是从1开始计算
获取匹配字符串的长度
方式1:

$str=abcdefg
echo `expr match "$str" '$substr'`#$substr是一个正则表达式的字符串  

方式2:

$str=abcd
echo `expr "$str" : '$substr'`#$substr是一个正则表达式的字符串

获取子串在字符串这的位置

str=cdcasdsab
echo `expr index "$str" dc` #1 输出1 是因为c最新被匹配到

获取子串

echo `expr subtr "$str" 2 4` #截取起始位置是2长度为4的字符串

注意以下涉及位置是从0开始计算
获取子串

${string:position} #获取子串从position位置开始
${string:position:length} #获取子串从position位置开始,长度为length的子串

同样也可以采取这样的方式获取参数

echo ${*:2} #输出参数中 第二个参数起始包括第二个参数的所有参数
echo ${@:2} #同上
echo ${*:2:3} #获取参数中,第二参数起,包括第二个参数的三个参数

其它

以下情况针对变量也可以。
删除字符串,从前开始

${str#substr} #返回删除substr后的字符串  懒惰模式
${str##substr} #尽可能多的删除掉匹配的substr  类似于正则中的贪婪模式

删除字符串从后开始

${string%sub}  #从字符串末尾位置开始删除sub子串 懒惰模式
${string%%sub} #从字符串末尾位置开始尽可能多的删除sub子串  贪婪模式

字符串替换

${str/substr/rep} 替换查找到的第一个substr为rep
${str//substr/rep}替换查找到所有的substr为rep
${str/#substr/rep}替换查找从前往后查找的第一个substr为rep
${str/%substr/rep}替换查找从后往前的第一个substr为rep

函数

函数中获取参数,注意函数值的 1, 1是不一样的,函数中的 1使 1变量

func (){
    echo $1
}

获取命令的执行结果

chars=$(cat /etc/password)

chars 变量的值就是执行car /etc/password的结果

可以进行命令拼接

#!/bin/bash
for file in $(ls $1.log.* );do #查找当前目录中匹配 $1.log.*  的日志文件
    echo $file
done

脚本中获取Linux信号

#!/bin/bash
trap 'echo "exit now" ' 2 3 15 19 #当接收到 CTRL+C 或者退出  命令时直接输出
trap '' 2 #直接忽略CTR+C信号,当在命令行狂按CTR+C时,没有被处理
trap 2 #按默认方式去处理
testFunc()
{
    echo "test"
}   
##也可以在shell脚本内调用函数:
trap testFunc 2

需要注意的是 SIGKILL,SIGTERM 信号机制,当接收到此命令时 shell脚本不能做任何处理
信号机制的含义详见附录表.

参数替换

${parameter-default}${parameter:-default}差异

If parameter not set, use default.

asdasd=456

var1=${www:-asdasd}
echo var1 #输出456

unset var1
var1=
var1=${www:asdasd}
echo $var1 # 没有输出信息

当var1 声明,但是值为null时,${parameter:default}不会输出值
赋值时需要注意

echo ${var=abc} #输出var的值为abc
echo ${var=xyz}#输出var的值为abc,var的值已经赋值不会改变,也就是说对于已经赋值的变量不会改变其值

${parameter=default}, ${parameter:=default}

If parameter not set, set it to default.

${parameter+alt_value},${parameter:+alt_value}

If parameter set, use alt_value, else use null string.

${parameter?err_msg}, ${parameter:?err_msg}

If parameter set, use it, else print err_msg and abort the script with an exit status of 1.

输入输出重定向

输出、输入重定向

#错误输出重定向
ls 2 > file 
#错误输出与标准输出重定向,将错误输出当做标准输出
ls > file 2>&1
#错误输出与标准输出重定向
ls &> file
#标准输出当做错误输出
ls 2>file 1>&2

#输入重定向
ls < file

注意事项

1.给变量赋值时 =两边不要存在空格,否则会当成命令进行执行
2. ?03. @是所有的参数列表,#为参数的个数  
4.
!是该执行脚本的PID
5.脚本中单引号不可包含变量,双引号字符串换可以
6.多个语句写在同一行需要用 ;进行分割
7. 中间的command可以赋值于变量,执行后的输出
8. command &> filename 重定向输出错误与标准输出
9. 在脚本中需要使用设置别名时,在脚本前先需执行,shopt -s expand_aliases

技巧

1.赋值字符串也可以不要引号

var1=123\ water
echo $var1 #123 water

补充我们也可以多行输入

echo 123\
456
#123456 输出一行

2.赋值ASCII码值
3.输出bash的版本号

echo $BASH_VERSION

4.输出脚本的执行栈

sh -x test.sh #检测脚本的执行栈错误

5.检测shell脚本的语法错误

sh -n test.sh #检测test.sh是否存在语法错误

6.脚本内设置$1...$n参数

#!/bin/bash
set -- "First param" "Second param"

7.声明变量的类型

#!/bin/bash
declare -i  var1 #声明一个整形变量
declare -f function_name #声明一个函数
declare -a array1 #声明一个数组
declare -r var1=1 #声明一个只读变量,如果被重新赋值,直接报错
export NAME="lzx"  #定义一个全局变量,永久生效,针对单一用户,在定义全局变量之前一定要,了解相关的环境变量,避免覆盖

8.获取变量名称,从变量的名称获取变量的值

#!/bin/bash
var1=123
var2=234
${var!var*} #变量var的值为 var1 var2
for i in $var;do
    echo ${i} #123 234
done    

9.将循环中生成的变量

#!/bin/bash
var=`for i in $(seq 10)
do
echo $i
done
`#var的值为 1 2 ... 10

需要注意:shell脚本默认定义的变量是global类型,从定义开始到脚本结束,或者被显示删除的,
local定义的变量为局部变量,与global同名的变量会被替代,作用域为声明的函数内(只在函数内声明)。

#!/bin/bash
func1(){
 loacal a=10
}

10.shift用法
遍历输入参数

for in $@;do
 echo $1
 shift
done

10.getopts 获取参数
在编写shell脚本的时候我们经常会遇到简称的采用, -a 123 -b 456
两个需要关注的变量
$OPTARG 当前选项的值
$OPTIND当前选项索引值,从1开始计算
第一个冒号表示忽略参数错误,参数选项不正确默认情况会报错,
选项后的冒号表示,该选项需要参数值

while getopts ":a:b:c" opt
do
    case $opt in
        a)
            echo $OPTARG
        b)
            echo $OPTARG
    esac            
done

11.引用其他文件
方便业务的模块化
source, .命令都支持传参

. "filename"
source "filename" 123 456

12.可以给函数使用重定向,或者管道进行输入和输出,管道需要嵌套block,

func(){

} < /tmp/data

func(){
    {
        echo $*
    } | tr a b  
} 

13.函数的递归调用

斐波那契数列 递归调用,非常慢。
摘自asb-guide

#!/bin/bash
MAXTERM=15 # Number of terms (+1) to generate.
MINIDX=2 # If idx is less than 2, then Fibo(idx) = idx.
Fibonacci ()
{
 idx=$1 # Doesn't need to be local. Why not?
 if [ "$idx" -lt "$MINIDX" ]
 then
 echo "$idx" # First two terms are 0 1 ... see above.
 else
 (( --idx )) # j-1
 term1=$( Fibonacci $idx ) # Fibo(j-1)
 (( --idx )) # j-2
 term2=$( Fibonacci $idx ) # Fibo(j-2)
 echo $(( term1 + term2 ))
 fi
 # An ugly, ugly kludge.
 # The more elegant implementation of recursive fibo in C
 #+ is a straightforward translation of the algorithm in lines 7 - 10.
}
for i in $(seq 0 $MAXTERM)
do # Calculate $MAXTERM+1 terms.
 FIBO=$(Fibonacci $i)
 echo -n "$FIBO "
done
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610
# Takes a while, doesn't it? Recursion in a script is slow.
echo
exit 0

14.声明函数的另一种方式
需要注意的是,for循环遍历这样的数组时,不能被正常的

#!/bin/bash
arr=( [0]="one two" [1]="three four" [3]="five" )
echo ${arr[0]}#one two

15.根据变量值获取另一个变量值

$var=a
$a=456
echo "$$var" #456

附录表:

文件相关
-e filename 如果filename存在则为真
-r filename 如果文件存在且可读为真
-w filename 如果文件存在且可写为真
-x filename 如果文件存在可写为真
-d filename 如果文件存在且为目录为真
-f filename 如果文件存在且为普通文件为真

字符串相关
==,!= 判断字符串相等或者不等
-z 判断字符串长度为0则为真
-n 判断字符串长度不为0则为真

全局变量
$UID只有当值为0时,执行脚本的权限为root权限
$PPID获得进程的父进程的ID号
$IFS数组分割的变量,改变其值会影响$@, $*参数的值
$0当前执行脚本的名称,注意使用sh test.sh会输出test.sh 如果使用路径执行./test.sh会输出./test.sh
$* 与 $@类似,获取输入参数
$$改脚本执行的PID
$?获取函数的返回值,命令最后一个执行的结果
$#获取脚本的参数的个数
$!获取最后一个运行在后台的进程ID

全局函数
$RANDOM内部函数,生成一个0-32767的随机数,是一个函数并不是常量

Linux常用信号机制表
SIGHUP 1 终端的挂断或进程的死亡
SIGINT 2 来自键盘的中断信号^+C
SIGQUIT 3 来自键盘的退出信号^+\
SIGKILL 9 杀死进程的信号
SIGTERM 15 终止信号 无法被trap捕获
SIGALRM 14 收到alarm信号

Bash 4以上新特性

associative array

example

arr[index1]="value"
arr[index2]="value"

case结构体
case结构体当中的;;是默认不贯穿执行的
;;& 表示执行到下个case语句,通过case条件判断
;& 不管case条件是否通过都执行下个语句,不推荐使用这个符号,破坏了case语言的结构

test_func(){
    case "$1" in
        1) echo "number one";;&
        2) echo "number two";;
        3) echo "number three";&
        4) echo "number four";;
}
test_func 1#输出number one不符合下个的case条件
test_func 3#输出number three number four

declare 支持-l (lowercase) -c (capitalize)

表达式支持增量设置
{40..60..2}

**操作符 可以递归的遍历文件
前提条件是在脚本开始处

shopt -s globstar
for filename in **
do 
    echo $filename
done    
exit

内置的错误
command_not_found_handle
在bash中调用一个没有定义的命令 会抛出对应的异常
example

command_not_found_handle ()
{ 
 echo "The following command is not valid: \""$1\"""
 echo "With the following argument(s): \""$2\"" \""$3\""" # $4, $5 ...
}

你可能感兴趣的:(bash,shell)