输出读取文件的的每一行
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命令基本等价于 []
用法示例:
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] #删除指定的元素
其它的截取、替换、删除不在赘述,详情参照字符串,使用方法与字符串类似,只是作用的元素不一样。
[]
变量与[
或者]
需要空格隔开
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条件判断中,无需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
#!/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. ?这个变量存储的是最近的命令的执行结果0执行正确其它执行错误3. @是所有的参数列表,#为参数的个数
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信号
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 ...
}