shell脚本在linux下开发经常需要用到,shell的脚本可以帮助用户自动化地和操作系统进行交互,起到了提高效率的作用。
调试
学习一门语言,通常需要实战演练编码调试,shell该如何调试呢?使用bash -x
命令即可。
vi demo.sh
敲入代码:
#!/bin/bashecho 1;echo $(date +'%Y-%m-%d'); |
执行bash -x demo.sh
将输出
+ echo 1 #代码1 #运行结果++ date +%Y-%m-%d #嵌套代码+ echo 2014-10-30 #代码2014-10-30 #运行结果 |
可以看到,bash会先输出代码,再输出运行结果,前面带+号表示这是一行shell代码,多个+号表示代码有嵌套逻辑。
更多调试方法见传参
如何从命令外部传递参数到脚本里头?
#!/bin/bashecho $0 #脚本名echo $1 #第一个参数echo ${2} #第2个参数echo $# #参数总数(不含$0)echo $* #所有参数(不含$0) |
执行bash demo.sh aa bbb ccc dddd
将输出:
demo.shaabbb4aa bbb ccc dddd |
$*
和 $@
的区别?
但是当它们被双引号(
$*
和$@
都表示传递给函数或脚本的所有参数,不被双引号("
"
)包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。"
"
)包含时,"$*"
会将所有的参数作为一个整体,以"$1 $2 … $n"
的形式输出所有参数;"$@"
会将各个参数分开,以"$1"
"$2"
…"$n"
的形式输出所有参数。
变量
命名
变量的命名语法是:
- 符合正则
[a-zA-Z-][a-zA-Z\-0-9]
,也就是由大小写字母、数字、-
符号组成的字符串,不能以数字开头。 - 非系统缺省关键字,如
PATH
赋值与读取
赋值时等号两边不能带空格,否则会报错。
#字符串变量赋值name=wang age="100" #数组变量赋值(3种方式)array_name1=(value1000 value11 value12 value13)array_name2=( value20 value21 value22 value23)array_name3[0]=value30array_name3[1]=value31array_name3[2]=value32#双引号内使用变量,单引号不识别内部变量。echo "双引号:$name is ${age} years old." echo '单引号:$name is ${age} years old.' #不使用双引号echo 不使用双引号:${name} is $age years old. #读取数组元素echo "数组元素:${array_name1[2]} ${array_name2[2]} ${array_name3[2]}"; #使用@ 或 * 可以获取数组中的所有元素,例如:echo "数组@:${array_name1[@]}" echo "数组*:${array_name1[*]}"#取得数组元素的个数echo "数组元素的个数:${#array_name1[@]} ${#array_name3[*]}"#取得数组单个元素的长度echo "数组单个元素的长度:${#array_name1[0]}" |
将输出
双引号:wang is 100 years old.单引号:$name is ${ age} years old.不使用双引号:wang is 100 years old.数组元素:value12 value22 value32数组@:value1000 value11 value12 value13数组*:value1000 value11 value12 value13数组元素的个数:4 3数组单个元素的长度:9 |
风格
使用变量可以是$name
或者${name}
的形式,注意有别于php字符串内变量{$name}
。${!name}
表示可变变量,类似于php的$$name
。
# Goodprefix="pre"echo "${prefix}_dir/file"# Bad# 会把prefix_dir视为变量名,由于无定义,会输出/file,若设置了set -u,则会报错。prefix="pre"echo "$prefix_dir/file" |
流程控制
if else
语法特点为:
- 条件使用中括号包围:
[[ condition ]]
或者[ condition ]
(注意中括号内前后都需要带空格) if
/elif
后condition
前带空格,下一行需要使用then
语句,也可以通过分号合并成一行if [[ condition ]]; then
- 以
fi
结尾
if [[ 0 -eq 2 ]]then echo 'if'elif [ 2 ]; then echo 'else if'else echo 'else'fi |
条件表达式
- 数值
-eq
相等(equal)-ge
大于等于(greater than or equal)-gt
大于(greater than)-ne
不等(not equal)-le
小于等于(less than or equal)-lt
小于(less than)
- 字符串
=
等于!=
不等于-z
字符串空-n
字符串非空
- 文件状态
-e
存在-s
存在且非空-f
存在且普通文件-r
存在且可读-w
存在且可写-x
存在且可执行-d
存在且目录
- 逻辑操作
-a
与(and)-o
或(or)!
非&&
||
用于条件外部
例如
[ 1 -lt 2 ]echo $? #true[ "a" != "a" -o "b" = "c" ] echo $? #false[ "a" != "a" ] || [ "b" = "c" ]echo $? #false |
switch
for
#从标准输出获取数组list1=$(echo 'aaa bbb ccc ddd' | awk '{print $1,$2}')for i in ${list1[@]}{ echo $i}#初始化数组list2=(1 2 3 4)for i in ${list2[@]}do echo $idone#构建循环条件列表for i in {a..z}{ for j in { 1..3} { printf "${i}${j} " }} |
while
函数
function foo() { #函数定义 echo $1 #参数1 echo $2 #参数2 local bbb="bbb" #局部变量 echo ${bbb} return 22; #返回值}foo 123 abcecho $? |
将输出
123abc22 |
命令替换
echo $(pwd) #语法可读性更好,且支持嵌套echo `pwd` |
算数计算
使用$(())
, 不使用let
# i自增1$(( i += 1 ))# 复杂的算数计算min=5sec=30echo $(( (min * 60) + sec )) |