调试脚本

检查脚本语法错误

bash -n /path/to/some_script


调试执行

bash -x /path/to/some_script


shell里的变量

    本地变量:只对当前shell有效;作用范围可以是整个shell程序文件,包括脚本中的函数,对其他的shell无效。
    环境变量:对当前shell及子进程shell有效。
    声明、赋值:export name=value 或者 declare -x name=value
    局部变量:与函数的生命周期一样;
        定义:local name=value
    位置变量:$1,$2,…,表示脚本传入的第几个参数
    特殊变量:$?(上一条命令执行结果代码),$0(当前脚本名称),$#(脚本参数个数)
    注:在用完变量之后要unset 变量名,这是个好习惯。

退出状态

进程使用退出状态来报告命令执行成功或失败

    0代表成功,1-255表示失败,系统通过数字来指定特定的错误

    $?保存最近的退出状态,用来判断执行命令是否成功

    不过我们在脚本里可以自定义退出状态码,用exit [n] 定义

        注意:脚本中一旦遇到exit 命令,脚本会立即终止;终止退出状态取决于exit 命令后面的数字
        注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

shell里的算术运算

算术运算符:+,-,*,/,%,** (乘法符号有些场景中需要转义 ,如*),算术表达式里的变量可以不加$,以下是实现算术运算并赋值的几种形式

    let var=算术表达式
    注意:let和expr运算符只要后面表达式执行结果为0,会返回错误代码1,写脚本做运算的时候注意!!!
    这里有个特殊例子:let k++ 和 let ++k 前面的返回1,后面的返回0

    var=$((算术运算符))
    var=$[算术运算符]
    var=$(expr arg1 运算符 arg2)
    注意:expr数字与运算符之间要有空格,否则会报错,参数除数字之外要加$
    declare -i var=value 声明变量val为数值,感觉这个和普通声明没有太大区别
    echo `算术表达式` | bc
    $RANDOM (0-32767)
    例:echo $[$RANDOM%50] :0-49

shell里的逻辑运算

逻辑运算就与(&&)或(||)非(!)
与:
1 与 与 1 = 1
1 与 与 0 = 0
0 与 与 1 = 0
0 与 与 0 = 0
或:
1 或 或 1 = 1
1 或 或 0 = 1
0 或 或 1 = 1
0 或 或 0 = 0
以上相信大家比较熟悉,下面简单介绍下逻辑短路。
短路与:
第一个为0 ,结果必定为0
第一个为1 ,第二个必须要参与运算
短路或
第一个为1 ,结果必定为1
第一个为0 ,第二个必须要参与运算
shell条件测试

在另一篇博客已经说了基础知识,下面简单说一下要注意的地方
测试命令有3种
test expression
[ expression ]
[[ expression ]]
注意:expression前后必须有空格;值为空或不赋值时结果为假,所有要加上引号。

[zhang@centos7 MyShell]$ [ a=b ] #操作法两边要加上空格,否则系统认为是整体会一直为真
[zhang@centos7 MyShell]$ echo $?
0
[zhang@centos7 MyShell]$ [ a = b ] #字符串要写成"$a",和算术运算不一样
[zhang@centos7 MyShell]$ echo $?
1
[zhang@centos7 MyShell]$ [ $a = $b ] #这个虽然可以,以防万一要加上双引号,这种情况下面介绍
[zhang@centos7 MyShell]$ echo $?
0



[ -n “$var” ] 这是正确写法,下面代码来说明一下

[zhang@centos7 MyShell]$ echo "$ab" #ab为空
[zhang@centos7 MyShell]$
[zhang@centos7 MyShell]$ [ -n $ab ] && echo true #而ab为空显示true
true
[zhang@centos7 MyShell]$ [ -n "$ab" ] && echo true #这个是正确结果
[zhang@centos7 MyShell]$


[ 条件1 -a 条件2 ] 和 [[ 条件1 && 条件2 ]] 这里面的逻辑运算是一样的,里面没有逻辑短路问题,不过后面可以接与或逻辑短路。

数值比较用 -eq,-ne…
字符串比较用 ==,>,<…
字符串比较可以匹配正则表达式但是要用[[ “$var” =~ 正则表达式 ]],正则表达式不用加双引号。

 

变量

和其它语言一样Shell中也有变量, 而且更简单, 但有一些比较特殊的地方.

  1. Shell中的变量只有字符串这一种类型
  2. Shell中变量名与变量值没有长度限制
  3. Shell的变量也允许比较操作和整数操作, 只要变量中的字符串为数字

定义变量

需要注意: = 两边不能加空格, 当赋值语句包含空格时请加引号(单引号/双引号均可)比如: 1

variable_name="ghui's blog"

Shell中的变量可以分为两种类型:

  1. 局部变量 (定义变量时在前面加local修饰符)
  2. 全局变量 (定义变量时不加任何修饰符)

与其它语言一样局部变量的可见范围是代码块或函数内, 全局变量在全局范围内可见.看个简单的例子:

num=111 
func1()
{
  local num=222 
  echo $num
  }
echo "before---$num"
func1
echo "after---$num"

输出:

before---111
222
after---111

使用变量

使用一个定义过的变量, 只要在变量名前面加$即可, 如:

name=ghui
echo $name
echo ${name}

在使用变量时还有一个地方需要注意, 请看下面的例子:

str='abc'
echo "1 print $str"
echo '2 print $str'

输出:

print abc
2 print $str

即: 被双引号括起来的变量会发生变量替换, 单引号不会

注释

Shell中注释使用#, 而且它不支持多行注释.

常用的字符串操作

字符串拼接

name="shell"
sayHi="hello, "$name" !"
sayHi2="hello, ${name} !"
echo $sayHi $sayHi2

注意: 上面说的单双引号引起的变量替换问题

获得字符串长度

string="abcd"
echo ${#string}

截取字符串

str="hello shell"
echo ${str:2}  
echo ${string:1:3}

更多关于字符串的操作可以看这个

if/else流程控制

基本语法结构:

if condition
then 
	 do something
	 elif condition
then 
	do something
	elif condition
then 
	do something
	else
	do something
	fi

其中, elif语句和else语句非必须的.看个例子:

a=1
if [ $1=$a ]
then
	echo "you input 1"
	elif [ $1=2 ]
then
	echo "you input 2"
	else
	echo " you input $1"
	fi

很简单, 不过这里有两个地方需要注意, 如果某个条件下的执行体为空, 则你就不能写这个条件 即下面这样会报错:

if condition
then 
	#do nothing
	elif condition
then 
	# do nothing
	#or
else
	#do nothing

另外, [ ] 两边一定要加空格, 下面这样都会报错:

if [$a=$b]
#or 
if [ $a=$b]
#or 
if [$a=$b ]

只有这样if [ $a=$b ]才是对的. 注意: 实际上这里的[]test命令的一种形式, [是系统的一个内置命令,存在路径是/bin/[,它是调用test命令的标识, 右中括号是关闭条件判断的标识, 因此下面的两个测试语句是等效的:

if test "2>3"
then
	...
	fi

if [ "2>3" ]
then 
	...
	fi

[]之外, shell语言中还有几种其它括号, 比如: 单小括号/双小括号/双中括号/… , 不同的括号有不同的用法, 更多关于shell中, 括号的用法可以看看这个

switch流程控制

当条件较多时, 可以选择使用switch语句, shell中的switch语句的写法和其它语言还是有些不同的, 基本结构如下:

case expression in
	pattern1)
		do something... ;;
	pattern2)
		do something... ;;
	pattern2)
		do something... ;;
	...
	esac

看个例子:

input=$1
case $input in
        1 | 0)
        str="一or零";;
        2)
        str="二";;
        3)
        str="三";;
        *)
        str=$input;;
        esac
echo "---$str"

这个例子会根据你执行此脚本时传入的参数不同在屏幕上输出不同的值, 其中第一个case 1 | 0代表逻辑或. NOTE:

  1. ;;相当于其它语言中的break
  2. 每个pattern之后记得加)
  3. 最后记得加esac (即反的case)

for循环

基本结构:

for name [in list]
do
	...
	done

其中,[]括起来的 in list, 为可选部分, 如果省略in list则默认为in "$@", 即你执行此命令时传入的参数列表. 看个例子:

for file in *.txt
do
	open $file
	done

遍历当前目录下的所有txt文件, 并依次打开.

while循环

基本结构:

while condition
do
	do something...
	done

看个例子:

i=0
while ((i
do
	((i++))
	echo "i=$i"
	done

输出:

NOTE: 你可能需要去了解一下(())的用法

until循环

基本结构

until condition
do
	do something...
	done

看个例子:

i=5
until ((i==0))
do
	((i--))
	echo "i=$i"
	done

输出:

跳出循环

shell中也支持break跳出循环, continue跳出本次循环.用法与C, Java中相同

函数

要定义一个函数, 可以使用下面两种形式:

function funcname()
{
	do something
	}

或者

funcname ()
{
	do something
	}

看个例子

add()
{
	let "sum=$1+$2"
	return $sum
	}
add $1 $2
echo "sum=$?"

输入

输出

其中, $?在shell中保存的是上一条命令的返回值

NOTE:

  1. 函数必须先定义后使用
  2. 如果在函数中使用exit会退出脚本, 如果想退回到原本函数调用的地方, 则可使用return

向脚本传递参数

先shell脚本传递参数, 非常简单, 只需要在你执行命令的后面跟上即可, 看个例子:

echo "$# parameters";
echo "$@";
echo "$0"
echo "$1"

输入:

输出:

2 parameters
11 22
test.sh
11

解释: $@代表所有参数的内容, $#代表所有参数的个数, $0代表脚本的名称, $1代表第一个参数的值.

 

 =================================