一、调试脚本

调试功能是每一种编程语言都应该实现的重要特性之一,当出现一些始料未及的情况时,用它来生成脚本运行信息。调试信息可以帮你弄清楚是什么原因使得程序发生崩溃或行为异常。每位系统程序员都应该了解Bash提供的调试选项。

shell脚本调试不需要什么特殊的工具。bash自带了一些调试选项。具体选项包含:
-x : 在执行时显示参数和命令;
+x:禁止调试
-v:当命令行进行读取时显示输入;
+v:禁止打印输入。
在shell脚本启动时或者在脚本内都可以添加这些调试选项。测试脚本debug.sh,代码如下所示。

#!/bin/bash
for i in {1..6};
do
echo $i
done
echo "Script executed"

直接运行脚本: ./debug.sh。 结果如图:

 

在脚本启动时添加调试选项。来调试debug.sh,可以在启动脚本时,输入以下命令:bash -x ./debug.sh 或者 sh -x ./debug.sh。结果如图:

 

在脚本内添加调试选项,使用set 命令。例如:
要开启-x选项,则在脚本内容中添加命令:set -x ,对应的set +x 是关闭调试。

#!/bin/bash
for i in {1..6};
do
set -x
echo $i
done
echo "Script executed
 "

现在要看debug.sh脚本执行的调试信息,就不需要使用bash -x ./debug.sh执行了。直接./debug.sh 就可以看到调试信息。结果:

还有一种更便捷的方法,就是在脚本开头添加-xv选项:

#!/bin/bash -xv
for i in {1..6};
do
echo $i
done
echo "Script executed”
 

同样现在执行./debug.sh,也可打印出调试信息。

 

前面介绍的调试手段是Bash内建的。它们通常以固定的格式生成调试信息。但是在很多情况下,我们需要以自定义格式显示调试信息。这可以通过传递 _DEBUG环境变量来建立这类调试风格。 请看下面的代码script.sh:

#!/bin/bash
function DEBUG()
{
[ "$_DEBUG" == "on" ] && $@ || :
}
for i in {1..10}
do
DEBUG echo $i
done

可以将调试功能置为"on"来运行上面的脚本:

_DEBUG=on ./script.sh

如果不开启调试开关,就直接执行./script。


二、函数和参数

inux shell 可以用户定义函数,然后在shell脚本中可以随便调用。
shell中函数的定义格式如下:

[ function ] funname [()]
{
action;
[return int;]
}
说明:
1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)

下面的例子hanshu.sh定义了一个函数并进行调用:
只需要使用函数名就可以调用某个函数: $ fname ; #执行函数

#!/bin/bash
function fname()
{
echo "这个我的第一个函数!!!"
}
echo "---函数开始执行---"
fname
echo "---函数执行完毕---"

结果如下图:

参数可以传递给函数,并由脚本进行访问:

fname arg1 arg2 ; #传递参数

以下是函数fname的定义。在函数fname中,包含了各种访问函数参数的方法。

#!/bin/bash
fname()
{
echo $1, $2; #访问参数1和参数2echo "$@";#以列表的方式一次性打印所有参数
echo "$*"; #类似于$@,但是参数被作为单个实体 return 0; #返回值
return 0;
}
fname 1 2 3

结果如下:

 $1是第一个参数。
 $2是第二个参数。
 $n是第n个参数。
 "$@" 被扩展成 "$1" "$2" "$3"等。
 "$*" 被扩展成 "$1c$2c$3",其中c是IFS的第一个字符。
 "$@" 要比"$*"用得多。由于 "$*"将所有的参数当做单个字符串,因此它很少被使用。

三、将命令序列的输出读入变量

shell脚本最棒的特性之一就是可以轻松地将多个命令或工具组合起来生成输出。一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递至另一个命令,依次类推。
这种命令组合的输出可以被存储在一个变量中。这则攻略将演示如何组合多个命令以及如何读取其输出。

(1) 先从组合两个命令开始:
ls | cat -n > out.txt
ls的输出(当前目录内容的列表)被传给cat -n,后者将通过stdin所接收到输入内容加上行号,
然后将输出重定向到文件out.txt。 (2) 我们可以用下面的方法读取由管道相连的命令序列的输出:这种方法被称为子shell。
例如:cmd_output=$(ls | cat -n)
echo $cmd_output
另一种被称为反引用(有些人们也称它为反标记)的方法也可以用于存储命令输出。
例如:cmd_output=`ls | cat -n`
echo $cmd_output

有很多种方法可以给命令分组。来看看其中的几种:
1、利用子shell生成一个独立的进程子shell本身就是独立的进程。可以使用()操作符来定义一个子shell

pwd;
(cd /bin; ls);
pwd;

当命令在子shell中执行时,不会对当前shell有任何影响;所有的改变仅限于子shell内。例如:当用cd命令改变子shell的当前目录时,这种变化不会反映到主shell环境中。

2、通过引用子shell的方式保留空格和换行符
假设我们使用子shell或反引用的方法将命令的输出读入一个变量中,可以将它放入双引号中,以保留空格和换行符(\n)。例如:

out=$(cat text.txt)
echo $out out="$(cat tex.txt)"
echo$out

四、Read函数

read是一个重要的Bash命令,它用于从键盘或标准输入中读取文本。

我们可以使用read以交互的形式读取来自用户的输入,不过read能做的可远不止这些。任何编程语言的输入库大多都是从键盘读取输入;但只有当回车键按下的时候,才标志着输入完毕。
在有些重要情形下是没法按回车键的,输入结束与否是基于字符数或某个特定字符来决定的。

例如,在一个游戏中,当 按下 + 键时,小球就会向上移动。那么若每次都要按下 + 键,然后再按回车键来确认已经按过 + 键,这就显然太低效了。

read命令提供了一种不需要按回车键就能够搞定这个任务的方法。

你可以借助read命令的各种选项来实现不同的效果。方法如下所示:
(1) 下面的语句从输入中读取n个字符并存入变量:

read -n 2 var
echo $var

(2) 用无回显的方式读取密码:

read -s var

(3) 显示提示信息:

read -p "Enter input:" var

(4) 在特定时限内读取输入:

read -t 2 var #在2秒内将键入的字符串,且键入回车后,读入变量var

(5) 用特定的定界符作为输入行的结束:

read -d ":" var 

hello:#var 被设置为 hello

(6)read命令是一个一个词组地接收输入的参数,每个词组需要使用空格进行分隔;如果输入的词组个数大于需要的参数个数,则多出的词组将被作为整体为最后一个参数接收。

read firstStr secondStr
echo "第一个参数:$firstStr; 第二个参数:$secondStr"
执行测试:
./test.sh
一 二 三 四
第一个参数:一; 第二个参数:二 三 四

五、运行命令直至执行成功

在日常工作中使用shell时,有时候命令只有满足某些条件或是某种外部事件(例如文件可以被下载)操作才能够成功执行。这种情况下,你可能希望重复执行命令,直到成功为止。

重复执行命令函数:
repeat() {while :;do $@ && return; done}

修改间隔时间后再次执行,默认会不断执行:

repeat() {while :; do  sleep 30; $@ && return ; done}

举例:

#!/bin/bash
repeat()
{
while :;
do
sleep 30 ;
$@ && return ;
done
}
echo "开始计时"
echo `date`
repeat pwd
echo `date`

运行脚本,等待30S后,在执行pwd。


六、字段分隔符和迭代器

内部字段分隔符(Internal Field Separator,IFS)是shell脚本编程中的一个重要概念。在处理文本数据时,它的用途可不小。我们将会讨论把单个数据流划分成不同数据元素的定界符 (delimiter)。内部字段分隔符是用于特定用途的定界符。IFS是存储定界符的环境变量。它是当前shell环境使用的默认定界字符串。
1、查看IFS的值

echo “$IFS"

直接输出IFS是看不到值的,转化为二进制就可以看到了:

echo "$IFS"|od -b
输出结果:
0000000 040 011 012 012
0000004
"040"是空格,"011"是Tab,"012"是换行符"\n" 。最后一个 012 是因为 echo 默认是会换行的。

2、IFS的默认值为空白字符(换行符、制表符或者空格)。
当IFS被设置为逗号时,shell将逗号视为一个定界符,因此变量$item在每次迭代中读取由逗号分隔的子串作为变量值。 如果没有把IFS设置成逗号,那么下面的脚本会将全部数据作为单个字符串打印出来。实例:

#!/bin/bash
data="name,sex,rollno,location"
old_IFS=$IFS
IFS=","
for item in $data;
do
echo Item: $item
done IFS=$old_IFS

输出结果:
Item: name
Item: sex
Item: rollno
Item: location


七、比较与测试

程序中的流程控制是由比较语句和测试语句处理的。Bash同样具备多种与Unix系统级特性相兼容的执行测试的方法。我们可以用if、if else以及逻辑运算符进行测试,用比较运算符来比较数据项。除此之外,还有一个test命令也可以用于测试。
来看看用于比较和测试的各种方法:

1、if条件
if condition;
then
commands; fi 2、else if和else
if condition;
then
commands;
else if condition; then
commands;
else
commands; fi

if和else语句可以进行嵌套。if的条件判断部分可能会变得很长,但可以用逻辑运算符将它变得简洁一些:

 [ condition ] && action; # 如果condition为真,则执行action;
 [ condition ] || action; # 如果condition为假,则执行action。
&&是逻辑与运算符,||是逻辑或运算符。编写Bash脚本时,这是一个很有用的技巧。

1、算数比较
条件通常被放置在封闭的中括号内。一定要注意在[或]与操作数之间有一个空格。如果
忘记了这个空格,脚本就会报错。

对变量或值进行算术条件判断:

[ $var -eq 0 ] #当$var 等于0时,返回真
[ $var -ne 0 ] #当$var 为非0时,返回真 其他重要的操作符如下所示:
 -gt:大于。
 -lt:小于。
 -ge:大于或等于。
 -le:小于或等于。 可以按照下面的方法结合多个条件进行测试:
[ $var1 -ne 0 -a $var2 -gt 2 ] #使用逻辑与-a
[ $var1 -ne 0 -o var2 -gt 2 ] #逻辑或 -o

脚本实例:

#!/bin/bash
var=133
if [ $var -ne 0 ]
then
echo True
else
echo Flase
fi 很明显,结果返回True.

2、字符串比较
使用字符串比较时,最好用双中括号,因为有时候采用单个中括号会产生错误,所以最好避开它们。
可以用下面的方法检查两个字符串,看看它们是否相同。

⚠️注:注意在 = 前后各有一个空格。如果忘记加空格,那就不是比较关系了,而变成了赋值语句。

[[ $str1 = $str2 ]]:当str1等于str2时,返回真。也就是说,str1和str2包含的文本是一模一样的。
[[ $str1 == $str2 ]]:这是检查字符串是否相等的另一种写法。也可以检查两个字符串是否不同。 [[ $str1 != $str2 ]]:如果str1和str2不相同,则返回真。 [[ $str1 > $str2 ]]:如果str1的字母序比str2大,则返回真。
[[ $str1 < $str2 ]]:如果str1的字母序比str2小,则返回真。 [[ -z $str1 ]]:如果str1包含的是空字符串,则返回真。
[[ -n $str1 ]]:如果str1包含的是非空字符串,则返回真。

脚本实例:

#!/bin/bash
str1=abcd
str2=dfgh
if [[ $str1 = $str2 ]]
then
echo True
else
echo Flase
fi 很明显,结果返回Flase.

使用逻辑运算符 && 和 || 能够很容易地将多个条件组合起来。 见实例:

#!/bin/bash
str1=abcd
str2=dfgh
if [[ $str1 = $str2 ]] && [[ $str1 != $str2 ]]
then
echo True
else
echo Flase
fi

test命令可以用来执行条件检测。用test可以避免使用过多的括号。见实例:

    if  [ $var -eq 0 ]; then echo "True"; fi
也可以写成:
if test $var -eq 0 ; then echo "True"; fi

3、文件系统相关测试
我们可以使用不同的条件标志测试不同的文件系统相关的属性。

[ -f $file_var ]:如果给定的变量包含正常的文件路径或文件名,则返回真。
[ -x $var ]:如果给定的变量包含的文件可执行,则返回真。
[ -d $var ]:如果给定的变量包含的是目录,则返回真。
[ -e $var ]:如果给定的变量包含的文件存在,则返回真。
[ -c $var ]:如果给定的变量包含的是一个字符设备文件的路径,则返回真。
[ -b $var ]:如果给定的变量包含的是一个块设备文件的路径,则返回真。
[ -w $var ]:如果给定的变量包含的文件可写,则返回真。
[ -r $var ]:如果给定的变量包含的文件可读,则返回真。
[ -L $var ]:如果给定的变量包含的是一个符号链接,则返回真。

脚本实例:

#!/bin/bash
fpath="/etc/passwd"
if [ -e $fpath ]; then
echo File exists;
else
echo Does not exist;
fi

以上,未完待续~~

 

Shell学习笔记二的更多相关文章

  1. shell 学习笔记二

    一.break命令 break命令允许跳出所有循环(终止执行后面的所有循环). 下面的例子中,脚本进入死循环直至用户输入数字大于5.要跳出这个循环,返回到shell提示符下,就要使用break命令. ...

  2. linux shell学习笔记二---自定义函数(定义、返回值、变量作用域)介绍

    linux shell 可以用户定义函数,然后在shell脚本中可以随便调用.下面说说它的定义方法,以及调用需要注意那些事项. 一.定义shell函数(define function) 语法: [ f ...

  3. Shell学习笔记(二)

    if 语句 最简单的用法就是只使用 if 语句,它的语法格式为: if condition then statement(s) fi condition是判断条件,如果 condition 成立(返回 ...

  4. 鸟书shell 学习笔记(二) shell中正則表達式相关

    通配符与正則表達式的差别 通配符是bash原生支持的语法,正則表達式是处理字符串的一种表示方式, 正則表達式须要支持的工具支持才干够 语系设置 : export LANG=C grep alias 设 ...

  5. SHELL学习笔记三

    SHELL学习笔记一 SHELL学习笔记二 SHELL学习笔记三 for 命令 读取列表中的复杂值 从变量读取列表 从命令读取值 更改字段分隔符 用通配符读取目录 which 使用多个测试命令 unt ...

  6. shell学习笔记汇总

    1.shell脚本中函数使用 函数定义在前,调用在后,顺序反了就没有效果了.函数调用为:函数名 参数列表 函数内部通过以下变量访问函数的参数:shell脚本函数中: $0: 这个脚本的名字 $n: 这 ...

  7. shell 学习笔记2-shell-test

    一.字符串测试表达式 前面一篇介绍:什么是shell,shell变量请参考: shell 学习笔记1-什么是shell,shell变量 1.字符串测试表达式参数 字符串需要用""引 ...

  8. MongoDB学习笔记二- Mongoose

    MongoDB学习笔记二 Mongoose Mongoose 简介 之前我们都是通过shell来完成对数据库的各种操作, 在开发中大部分时候我们都需要通过程序来完成对数据库的操作 而Mongoose就 ...

  9. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

随机推荐

  1. Gogs基本使用介绍

    Gogs简介 Gogs 是一款类似GitHub的开源文件/代码管理系统(基于Git),Gogs 的目标是打造一个最简单.最快速和最轻松的方式搭建自助 Git 服务.使用 Go 语言开发使得 Gogs ...

  2. Opengl正交矩阵 glOrthof 数学原理(转)

    http://blog.sina.com.cn/s/blog_6084f588010192ug.html 在opengles1.1中设置正交矩阵只要一个函数调用就可以了:glOrthof,但是open ...

  3. Django应用:学习日志网站

    目录 一.创建虚拟环境(Windows) 二.创建项目 三.创建应用程序 四.创建网页:学习笔记主页 五.创建其他网页 六.用户输入数据 七.用户账户 八.让用户拥有自己的数据 九.设置应用程序样式 ...

  4. windows7系统最大支持多少内存

      目前Windows 7 64位版仅能使用最大为192GB内存. 这是各个版本的具体数据:64位的Windows  7家庭普通版最高可支持8GB内存,家庭高级版最高可支持16GB内存,64位的Win ...

  5. Linux 内存使用率

    文章参考: 1.正确计算linux系统内存使用率 2.Linux系统内存消失与slab使用之谜 例如当前主机内存信息如下: [zhang@test ~]$ cat /proc/meminfo MemT ...

  6. SQL注入的绕过

    一.常用符号的绕过 1.空格 1 空格代替:+ %20 %09 %0a %0b %0c %0d %a0 %00 /**/ /*!*/ 2 括号绕过:常用于基于时间延迟的盲注,例如构造语句: ?id=1 ...

  7. ArcGIS栅格影像怎么从WGS84地理坐标转成Xian80投影坐标

    事情是这样的,我下载了一个WGS84坐标系的影像图,需要加载到Xian80投影坐标系下,所以需要对影像图进行坐标系的转换 1.因为涉及到两个参考椭球的问题,首先需要计算七参数,如何计算七参数,请参考我 ...

  8. Handler实现线程间的通信2

    与Handler实现线程间的通信1反过来MainThread中向WorkerThread中发送消息

  9. Linux基础第四课——文件操作

    文件的创建 touch sudo touch 文件1 文件2 文件3 #支持批量创建文件 sudo rm -f 文件1 文件2 文件3 #支持批量创建 也支持批量删除 echo '谁动谁输,对不起我输 ...

  10. ORB-SLAM2(2) ROS下配置和编译

    1配置USB相机 1.1网友参考: http://www.liuxiao.org/2016/07/ubuntu-orb-slam2-%E5%9C%A8-ros-%E4%B8%8A%E7%BC%96%E ...