13 数组
数组有两种:关联数据 索引数组
# 索引数组使用从 0 开始的整数下标,下标必须是非负的整数
# 关联数组使用字符串作为下标
# 可以使用 declare -a 数组名 来声明索引数组
# 必须使用 declare -A 数组名 来声明关联数组
13.1 数组创建
arr[0]=1
13.12 # 按指定的下标,因此下标可以不连续,可以不按由小到大的顺序
arr4=([0]="aaa" [3]="bbb" [2]="ccc")
13.13 # 下标是默认从 0 开始的连续下标
arr5=("111" "222" "333" "444")
13.2 数组引用
${arr[0]}
13.21 # 有指定下标和未指定下标混合使用时,--------------------- -------------------属于数组引用
# 从前往后,没有指定下标的默认从 0 下标开始,有指定下标的元素,
# 其后紧跟的未指定下标的元素,其下标递增,下标有重复的,
# 以最后出现的为准
13.22 # 关于索引数组的负数下标: ------------------------ 属于数组引用
# 如果下标为负,则表示从数组的最后元素开始倒数
# -1 表示最大下标的元素,-2 表示倒数第 2 个元素,依此类推
13.23# # 下标为 * 或 @ 时,表示数组的全部元素 ----------------------------- 属于数组引用
# 其中,* 表示以 "值1 值2 ..." 形式
# @ 表示以 "值1" "值2" ... 形式
57 arr=("aaaaa" "bbb" "ccc")
58
59 for a in "${arr[@]}";do
60 echo $a
61 done
13.3
# 求数组元素字符串长度:${#数组名[下标]}
echo "\${#arr5[0]}=${#arr5[0]}"
echo "\${#arr5}=${#arr5}"
# 求数组长度:${#数组名[*或@]}
# 如果索引数组中跳过了一些元素,则不计算长度
echo "\${#arr5[*]}=${#arr5[*]}"
echo "\${#arr4[@]}=${#arr4[@]}" # [2] 元素跳过了,因此长度少 1
13.4
# 由数组的下标可以产生一组值:${!数组名[*或@]}
# [*] 产生的值是整个由 "" 括住的,形如:"值1 值2 ..."
# [@] 产生的值每个值由一对 "" 括住,形如:"值1" "值2" ...
echo "\${!arr5[*]}=${!arr5[*]}"
echo "\${!arr5[@]}=${!arr5[@]}"
echo "\${!arr4[*]}=${!arr4[*]}"
echo "\${!arr4[@]}=${!arr4[@]}"
13.5
# 取消数组元素:unset 数组名[下标]
unset arr4[2] # 取消下标为 2 的元素
unset arr4[-1] # 取消最后一个元素
echo "\${#arr4[*]}=${#arr4[*]}"
# 取消整个数组:unset 数组名 或 unset 数组名[*或@]
unset arr5
echo "\${#arr5[*]}=${#arr5[*]}"
unset arr4[*]
echo "\${#arr4[*]}=${#arr4[*]}"
14 函数 没有参数($1 $2),没有返回值(返回值可以通过三种方式得到)
# shell 函数定义的格式:
# name () compound-command [redirection]
# function name [()] compound-command [redirection]
# 没有返回值类型
# 没有形参列表
# 使用 return 返回值,取值范围 0 - 255 之间
# 如果超这个范围,只取最低字节(无符号值)
# 使用全局变量带回值
# 通过 $1 $2 ... 传递参数
------------------------------------------------------------------------------
使用返回值
func1 ()
{
echo "func1 ()"
# 返回值 1
return 1
# return 257 # 257-256=1
}
func1
echo \$?=$? # 打印 func1 函数调用的返回值
------------------------------------------------------------------------------------------
使用全局变量
result=0
myadd ()
{
if (($# != 2)); then
echo "用法:$0 <num1> <num2>"
return 1
fi
# 使用 $1 $2 ... 传递参数
# 使用 全局变量 result 得到返回值
# 因此必须在调用此函数结束后,立即检查 result 的值
let result=$1+$2
}
//----------------------------------------------------------------------
通过第三个参数返回
# 将前两个参数相减,结果存入第 3 个参数
mysub ()
{
if (($# != 3)); then
echo "用法:$0 <num1> <num2> <reference>"
return 1
fi
# -n 选项声明 tmp 为第 3 个参数的引用
# tmp 因为是在函数内部使用的变量,因此它是函数的局部变量
# 也可以使用 local 显式声明一个局部变量
declare -n tmp=$3
let tmp=$1-$2
}
# 调用时第 3 个参数为 r,则可以通过 r 带回返回值
mysub $num2 $num1 r
echo "$num2 - $num1 = $r"
---------------------------------------------------------------------------------------
# 如果是组合命令,则可以不使用 {}
# 组合命令如下:
# 1. (list)
# 2. { list; }
# 3. ((expression))
# 4. [[ expression ]]
# 5. for name [ [ in [ word ... ] ] ; ] do list ; done
# 6. for (( expr1 ; expr2 ; expr3 )) ; do list ; done
# 7. select name [ in word ] ; do list ; done
# 8. case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
# 9. if list; then list; [ elif list; then list; ] ... [ else list; ] fi
# 10. while list-1; do list-2; done
# 11. until list-1; do list-2; done
# for in 循环就是一个组合命令
test () for v in 123 456; do echo $v; done
# 调用 test
test
----------------------------------------------------------------------------------
# 此脚本中要引用 funcs.sh 脚本中定义的一组函数,
# 必须 source funcs.sh 脚本
source ./funcs.sh ####脚本引用
14 read 命令的使用
read a b c
echo "$a $b $c"
read -p "请输入三个参数" a b c
echo "$a $b $c"
# 可以从管道中读取变量
#ls ../ | while read file; do echo "$file"; done
ls -i ../ | while read inode file; do echo "$inode-$file"; done
15 select 命令
# select 命令用 word ... 列表构建出一个菜单,供用户选择,
# 每选择一个序号,就将这个序号对应的 word 赋值给 name,
# 并且执行一次 list
# select name [ in word ] ; do list ; done
select a in aa bb cc ee ;do
echo $a
done
运行上面三条语句,得到
1)aa
2) bb
3)cc
4)dd
可以通得输入1 2 3 4 得到输出aa bb cc dd .但 这个是死循环,所以得有个break; 跳出语句,见下
----------------------------------------------------------------------选择一个后退出
select week in Monday Tuesday Wednesday Thursday Friday Saturday Sunday;
do
if [ -z "$week" ]; then
echo "选择错误!请重新选择!"
else
break
fi
done
echo "你选择了 $week"
---------------------------------------------------------------------------------------------------
16 脚本调试
# trap 命令用于捕获指定的信号并执行预定义的命令。
# 其基本的语法是: trap 'command' signal
# command 就是要执行的命令,可以是自定义的函数。
# 也就是说 command 是用来处理 signal 信号的命令。
# signal 是要捕捉的信号
# signal 可以是 Linux 系统预定义的信号(kill -l 命令可以查看)
# 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
# 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
# 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
# 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
# 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
# 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
# 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
# 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
# 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
# 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
# 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
# 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
# 63) SIGRTMAX-1 64) SIGRTMAX
# signal 还可以是 shell 内部自定义的信号(伪信号):
# EXIT 从一个函数中退出或整个脚本执行完毕
# ERR 当一条命令返回非零状态时(代表命令执行不成功)
# DEBUG 脚本中每一条命令执行之前
从上面可以看出, trap 命令要求两个参数
'command' 可以是一个命令, 也可以是一个函数
signal 信号
73 handle_exit ()
74 {
75 echo rvc a signal
76 }
77 trap 'handle_exit' EXIT
----------------------------运行上面,可以在shell结束后打印 rvc a signal
79 handle_err ()
80 {
81 echo "this is a err"
82 }
83 trap 'handle_err' ERR
84
85 aaaa
----------------------------------------------------在aaaa 处出错, 可以接收到 this is err
handler_debug ()
{
echo "$1 行:收到 DEBUG 信号, \$i=$2"
}
# 捕捉 DEBUG 信号
trap 'handler_debug $LINENO $i' DEBUG
for ((i=0;i<3;i++)); do
echo "\$i=$i"
done
----------------------------------------------------------------第一条语句,就一个handler_debug ()函数