Shell编程入门总结(三)
2016-04-30 13:56
609 查看
本文的主要内容:
1、数组
2、命令组合
3、进程替换
4、陷阱机制
5、常见错误与防错
一、数组
Bash 中的数组仅限制为单一维度。对数组的支持第一次出现在 bash 版本2中。
1.创建一个数组
$ a[1]=foo
$ echo ${a[1]}
foo
其中第一个命令把数组 a 的元素1赋值为 “foo”,第二个命令显示存储在元素1中的值。在第二个命令中使用花括号是必需的, 以便防止 shell 试图对数组元素名执行路径名展开操作
也可以用 declare 命令创建一个数组:
$ declare -a a
使用 -a 选项,declare 命令的这个例子创建了数组 a
2.数组赋值
有两种方式可以给数组赋值。
单个值赋值使用以下语法:name[subscript]=value
多个值赋值使用下面的语法:name=(value1 value2 ...)
例如:
$ days=(Sun Mon Tue Wed Thu Fri Sat)
$ days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)
3.输出整个数组的内容
下标 * 和 @ 可以被用来访问数组中的每一个元素
例如:
$ animals=("a dog" "a cat" "a fish")
$ for i in ${animals[*]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in ${animals[@]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in "${animals[*]}"; do echo $i; done
a dog a cat a fish
$ for i in "${animals[@]}"; do echo $i; done
a dog
a cat
a fish
4.确定数组元素个数
例如:
$ a[100]=foo
$ echo ${#a[@]} #数组元素个数
1
$ echo ${#a[100]} #第100元素的长度
3
尽管我们把字符串赋值给数组元素100,但bash仅仅报告数组中有一个元素,这不同于一些其它语言
5.找到数组使用的下标
因为 bash 允许赋值的数组下标包含“间隔”,确定哪个元素真正存在可以使用以下形式的参数展开:
${!array[*]}
${!array[@]}
例如:
$ foo=([2]=a [4]=b [6]=c)
$ for i in "${foo[@]}"; do echo $i; done
a
b
c
$ for i in "${!foo[@]}"; do echo $i; done
2
4
6
6.在数组末尾添加元素
使用 += 赋值运算符
例如:
$ foo=(a b c)
$ echo ${foo[@]}
a b c
$ foo+=(d e f)
$ echo ${foo[@]}
a b c d e f
7.数组排序
Shell 没有直接排序的方法,但可通过管道给sort实现
例如:
#!/bin/bash
# array-sort : Sort an array
a=(f e d c b a)
echo "Original array: ${a[@]}"
a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort))
echo "Sorted array: ${a_sorted[@]}"
8.删除数组
删除一个数组,使用 unset 命令:
$ foo=(a b c d e f)
$ unset foo
亦可用unset命令删除单个的数组元素:
$ foo=(a b c d e f)
$ unset 'foo[2]'
注:数组下标开始于0,数组元素用引号引起来可防止 shell执行路径名展开操作。
给一个数组赋空值不会清空数组内容:
$ foo=(a b c d e f)
$ foo=
$ echo ${foo[@]}
b c d e f
引用一个不带下标的数组变量,则指的是数组元素0:
$ foo=(a b c d e f)
$ echo ${foo[@]}
a b c d e f
$ foo=A
$ echo ${foo[@]}
A b c d e f
9.关联数组
例如创建颜色数组
declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"
访问关联数组元素:
echo ${colors["blue"]}
二、命令组合
用一个 group 命令,或者用一个子 shell可以把命令组合在一起
组命令:{ command1; command2; [command3; ...] }
注:花括号与命令之间必须有一个空格,并且最后一个命令必须用一个分号或者一个换行符终止
子 shell:(command1; command2; [command3;...])
例如:
可以用命令组合改为:
或
三、进程替换
1.当子 shell 退出时,环境副本会消失,所以在子 shell 环境(包括变量赋值)中的任何更改也会消失,例如:
echo "foo" | read
echo $REPLY
因为管道线中的命令总是在子 shell 中执行,所以该REPLY变量的内容总是为空
2.进程替换有两种表达方式:
一种适用于产生标准输出的进程:<(list)
另一种适用于接受标准输入的进程:>(list)
其中list 是一串命令列表
3.解决上面的 read 命令问题,可用进程替换,例如:
read < <(echo "foo")
echo $REPLY
4.进程替换允许我们把一个子 shell 的输出结果当作一个用于重定向的普通文件,检验如下:
$ echo <(echo "foo")
/dev/fd/63
使用 echo 命令,查看展开结果,我们看到子 shell 的输出结果,由一个名为 /dev/fd/63 的文件提供
5.例子:
这个循环对目录列表的每一个条目执行 read 命令。列表本身产生于该脚本的最后一行代码。这一行代码把从进程替换得到的输出 重定向到这个循环的标准输入。这个包含在管道线中的
tail 命令,是为了消除列表的第一行文本,这行文本是多余的。
四、陷阱(trap)机制
1.trap语法如下:
trap argument signal [signal...]
其中argument是一个字符串,它被读取并作为一个命令,signal 是一个信号的说明,它会触发执行所要解释的命令
2.例子:
此脚本定义一个陷阱,当脚本运行时每当接受到一个 SIGINT 或 SIGTERM 信号时,就会执行一个 echo 命令
五、常见错误与防错
1.语法错误
丢失引号:
......
if [ $number = 1 ]; then
echo "Number is equal to 1.
else
......
其中echo语句后面缺少一个引号
丢失或意外的标记:
......
if [ $number = 1 ] then
echo "Number is equal to 1."
else
......
其中if测试语句后面缺少一个分号
预料不到的展开
......
number=
if [ $number = 1 ]; then
......
其中当number展开后为[ = 1 ],若为测试语句的第一个参数添加双引号[ "$number" = 1 ]可更正此问题,此时展开后为[ "" = 1 ]
2.防错编程:验证假设
例如:
若dir_name所指的目录不存在则会删除当前工作目录中的所有文件
对此可将命令改为:
通常,当某种情况(比如上述问题)发生的时候,最好是终止脚本执行,并对这种情况提示错误信息:
3.其他防错技巧
验证输入
如:[[ $REPLY =~ ^[0-3]$ ]]
测试命令
如:echo rm *
将 rm 命令及其展开的参数列表打印出来,而不是执行实际的rm命令语句
使用echo输出变量内容
。。。
参考:《The Linux Command Line》
1、数组
2、命令组合
3、进程替换
4、陷阱机制
5、常见错误与防错
一、数组
Bash 中的数组仅限制为单一维度。对数组的支持第一次出现在 bash 版本2中。
1.创建一个数组
$ a[1]=foo
$ echo ${a[1]}
foo
其中第一个命令把数组 a 的元素1赋值为 “foo”,第二个命令显示存储在元素1中的值。在第二个命令中使用花括号是必需的, 以便防止 shell 试图对数组元素名执行路径名展开操作
也可以用 declare 命令创建一个数组:
$ declare -a a
使用 -a 选项,declare 命令的这个例子创建了数组 a
2.数组赋值
有两种方式可以给数组赋值。
单个值赋值使用以下语法:name[subscript]=value
多个值赋值使用下面的语法:name=(value1 value2 ...)
例如:
$ days=(Sun Mon Tue Wed Thu Fri Sat)
$ days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)
3.输出整个数组的内容
下标 * 和 @ 可以被用来访问数组中的每一个元素
例如:
$ animals=("a dog" "a cat" "a fish")
$ for i in ${animals[*]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in ${animals[@]}; do echo $i; done
a
dog
a
cat
a
fish
$ for i in "${animals[*]}"; do echo $i; done
a dog a cat a fish
$ for i in "${animals[@]}"; do echo $i; done
a dog
a cat
a fish
4.确定数组元素个数
例如:
$ a[100]=foo
$ echo ${#a[@]} #数组元素个数
1
$ echo ${#a[100]} #第100元素的长度
3
尽管我们把字符串赋值给数组元素100,但bash仅仅报告数组中有一个元素,这不同于一些其它语言
5.找到数组使用的下标
因为 bash 允许赋值的数组下标包含“间隔”,确定哪个元素真正存在可以使用以下形式的参数展开:
${!array[*]}
${!array[@]}
例如:
$ foo=([2]=a [4]=b [6]=c)
$ for i in "${foo[@]}"; do echo $i; done
a
b
c
$ for i in "${!foo[@]}"; do echo $i; done
2
4
6
6.在数组末尾添加元素
使用 += 赋值运算符
例如:
$ foo=(a b c)
$ echo ${foo[@]}
a b c
$ foo+=(d e f)
$ echo ${foo[@]}
a b c d e f
7.数组排序
Shell 没有直接排序的方法,但可通过管道给sort实现
例如:
#!/bin/bash
# array-sort : Sort an array
a=(f e d c b a)
echo "Original array: ${a[@]}"
a_sorted=($(for i in "${a[@]}"; do echo $i; done | sort))
echo "Sorted array: ${a_sorted[@]}"
8.删除数组
删除一个数组,使用 unset 命令:
$ foo=(a b c d e f)
$ unset foo
亦可用unset命令删除单个的数组元素:
$ foo=(a b c d e f)
$ unset 'foo[2]'
注:数组下标开始于0,数组元素用引号引起来可防止 shell执行路径名展开操作。
给一个数组赋空值不会清空数组内容:
$ foo=(a b c d e f)
$ foo=
$ echo ${foo[@]}
b c d e f
引用一个不带下标的数组变量,则指的是数组元素0:
$ foo=(a b c d e f)
$ echo ${foo[@]}
a b c d e f
$ foo=A
$ echo ${foo[@]}
A b c d e f
9.关联数组
例如创建颜色数组
declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"
访问关联数组元素:
echo ${colors["blue"]}
二、命令组合
用一个 group 命令,或者用一个子 shell可以把命令组合在一起
组命令:{ command1; command2; [command3; ...] }
注:花括号与命令之间必须有一个空格,并且最后一个命令必须用一个分号或者一个换行符终止
子 shell:(command1; command2; [command3;...])
例如:
ls -l > output.txt echo "Listing of foo.txt" >> output.txt cat foo.txt >> output.txt
可以用命令组合改为:
{ ls -l; echo "Listing of foo.txt"; cat foo.txt; } > output.txt
或
(ls -l; echo "Listing of foo.txt"; cat foo.txt) > output.txt
三、进程替换
1.当子 shell 退出时,环境副本会消失,所以在子 shell 环境(包括变量赋值)中的任何更改也会消失,例如:
echo "foo" | read
echo $REPLY
因为管道线中的命令总是在子 shell 中执行,所以该REPLY变量的内容总是为空
2.进程替换有两种表达方式:
一种适用于产生标准输出的进程:<(list)
另一种适用于接受标准输入的进程:>(list)
其中list 是一串命令列表
3.解决上面的 read 命令问题,可用进程替换,例如:
read < <(echo "foo")
echo $REPLY
4.进程替换允许我们把一个子 shell 的输出结果当作一个用于重定向的普通文件,检验如下:
$ echo <(echo "foo")
/dev/fd/63
使用 echo 命令,查看展开结果,我们看到子 shell 的输出结果,由一个名为 /dev/fd/63 的文件提供
5.例子:
#!/bin/bash # pro-sub : demo of process substitution while read attr links owner group size date time filename; do cat <<- EOF Filename: $filename Size: $size Owner: $owner Group: $group Modified: $date $time Links: $links Attributes: $attr EOF done < <(ls -l | tail -n +2)
这个循环对目录列表的每一个条目执行 read 命令。列表本身产生于该脚本的最后一行代码。这一行代码把从进程替换得到的输出 重定向到这个循环的标准输入。这个包含在管道线中的
tail 命令,是为了消除列表的第一行文本,这行文本是多余的。
四、陷阱(trap)机制
1.trap语法如下:
trap argument signal [signal...]
其中argument是一个字符串,它被读取并作为一个命令,signal 是一个信号的说明,它会触发执行所要解释的命令
2.例子:
#!/bin/bash # trap-demo : simple signal handling demo trap "echo 'I am ignoring you.'" SIGINT SIGTERM for i in {1..5}; do echo "Iteration $i of 5" sleep 5 done
此脚本定义一个陷阱,当脚本运行时每当接受到一个 SIGINT 或 SIGTERM 信号时,就会执行一个 echo 命令
五、常见错误与防错
1.语法错误
丢失引号:
......
if [ $number = 1 ]; then
echo "Number is equal to 1.
else
......
其中echo语句后面缺少一个引号
丢失或意外的标记:
......
if [ $number = 1 ] then
echo "Number is equal to 1."
else
......
其中if测试语句后面缺少一个分号
预料不到的展开
......
number=
if [ $number = 1 ]; then
......
其中当number展开后为[ = 1 ],若为测试语句的第一个参数添加双引号[ "$number" = 1 ]可更正此问题,此时展开后为[ "" = 1 ]
2.防错编程:验证假设
例如:
cd $dir_name rm *
若dir_name所指的目录不存在则会删除当前工作目录中的所有文件
对此可将命令改为:
[[ -d $dir_name ]] && cd $dir_name && rm *
通常,当某种情况(比如上述问题)发生的时候,最好是终止脚本执行,并对这种情况提示错误信息:
if [[ -d $dir_name ]]; then if cd $dir_name; then rm * else echo "cannot cd to '$dir_name'" >&2 exit 1 fi else echo "no such directory: '$dir_name'" >&2 exit 1 fi
3.其他防错技巧
验证输入
如:[[ $REPLY =~ ^[0-3]$ ]]
测试命令
如:echo rm *
将 rm 命令及其展开的参数列表打印出来,而不是执行实际的rm命令语句
使用echo输出变量内容
。。。
参考:《The Linux Command Line》
相关文章推荐
- shell读取文件每行,并执行命令
- Bash 下的快捷操作
- 03- Shell脚本学习--字符串和数组
- Mac下ProxyChains Tor实现shell代理,隐藏自己的ssh登陆ip
- Linux shell 统计访问日志
- bad interpreter: No such file or directory问题
- Shell编程入门总结(二)
- shell脚本
- Linux中的shell
- Linux shell中的I/O重定向相关(转)
- Xshell和Xftp的安装与使用教程
- Xshell使用
- IDC生产环境检测IP是否在用的Shell脚本
- Windows的cmd终端连接android手机运行adb shell脚本命令
- -bash: pod: command not found
- 关于node.js配置 Git Bash中node-v 显示command not found
- Shell数组的增删改查
- Linux系统的负载与CPU、内存、硬盘、用户数监控的shell脚本
- PowerShell Remove all user defined variable in PowerShell
- shell中date做循环变量,以及date简单解析