前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shell programming tutorial

shell programming tutorial

作者头像
s1mba
发布2018-01-03 18:59:37
1.4K0
发布2018-01-03 18:59:37
举报
文章被收录于专栏:开发与安全

可以直接 man bash 学习语法和相关命令。

一、什么是shell程序

以文件形式存放批量的Linux命令集合,该文件能够被Shell解释执行,这种文件就是Shell脚本程序

通常由一段Linux命令、Shell命令、控制语句以及注释语句构成

Shell 脚本的编写

Shell 脚本是纯文本文件,可以使用任何文本编辑器编写 Shell 脚本通常是以 .sh 作为后缀名 第一行:指定用哪个程序来编译和执行脚本。#!/bin/bash(shell 变量里面含 ! x 的话,要转义一下 \! x)

注释行:使用(#)符号;多行注释  <<EOD ... EOD

二、shell编程的主要内容

变量

本地变量、环境变量、位置参量

输入输出

read/echo或printf

条件测试

整数测试、逻辑测试、字符串测试

控制语句

条件/循环/分支/

函数 常用Shell程序内置指令

declare/export/eval/trap等

三、变量

(一)变量概述

(二)变量常见操作

(三)环境变量和只读变量

(四)位置参量(命令行参数)

 位置参量是一组特殊的内置变量,通常被 shell 脚本用来从命令行接受参数,或被函数用来保存传递给它的参数。

 执行 shell 脚本时,用户可以通过命令行向脚本传递信息,跟在脚本名后面的用空格隔开的每个字符串都称为位置参量。

在脚本中使用这些参数时,需通过位置参量来引用。例如: $1 表示第一个参数,$2 表示第二个参数,以此类推。 $9 以后需要用花

括号把数字括起来,如第 10 个位置参量以  ${10} 的方式来访问。

$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。但是当它们被双引号(" ")包含

时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。

注意 “$*” 受 $IFS 变量值的影响,如 

$ IFS=:;   $ set x y z   $ echo $*   x y z   $ echo "$*"   x:y:z   $ echo $@   x y z   $ echo "$@"   x y z  

使用$?判断管道的执行结果是否成功,不可信。因此在使用管道获取的参数,我们一定要增加对于参数的判断,或者,我们在sh和bash的解释器中,

增加set –o pipefail 的设置,可以让管道的执行结果是否成功,变得可信。

#例1:shell_test.sh  echo “the count of parameters:$#” echo “first param=$1” echo “second param=$2” echo “params’ string=$*”

shell_test.sh This is Peter

shell_test.sh This is "Peter Piper"    //如果位置参量中含有空格,则需要使用双引号

(五)数组

# 字典必须先声明

declare -A dic

dic=([key1]="value1" [key2]="value2" [key3]="value3")

#打印指定key的value

echo ${dic["key1"]}

#打印所有key值

echo ${!dic[*]}

#打印所有value

echo ${dic[*]}

四、输入输出

(一)输入--read命令

read var

从标准输入读取一行并赋值给变量var

read

标准输入读取一行并赋值给内置变量REPLY

read -a arr

读入一组词,依次赋值给数组arr

read -p "please input 5 digits:" -t 10 -a arr3  // -p 提示符 -t 超时

read -s // 输入不回显

stty -echo // 输入不回显    

stty echo // 输入回显

(二)输出--echo 命令

echo $num 或 echo ${num}   //输出一行文本

echo -n “Hello World”  // -n 去掉换行符 echo -e “\t” “Hello World”   // -e 支持转义

(三)echo输出颜色与光标定位:

\33[30m -- \33[37m   设置前景色(字体颜色) \33[40m -- \33[47m   设置背景色 \33[y;xH设置光标位置

echo –e “\033[31mthis is a test” echo -e "\033[10;5H\033[31m\033[46m this is a test“ echo -e "\033[0m" // 取消全部设置

五、算术扩展

(一)单引号、双引号、反引号区别

单引号 忽略所有特殊字符 双引号 忽略大部分特殊字符($,`, \ 等字符除外) 参考这里 或者尝试  X=*;   echo $X;   echo '$X';  echo "$X"; 的区别 反引号 命令替换(将一个命令的标准输出插入到命令的任何位置) $()     同上 命令替换可以嵌套  如果使用反引号,则内部的反引号必须用反斜杠来转义。

echo  `basename \`pwd\``

echo  $(basename  $(pwd))

算术运算符:

+、-、*、/(四则运算)

**、%      (幂运算 和 模运算,取余数)

<<、>>     (按位左移 和 按位右移)

&、^、|   (按位与 、按位异或 和 按位或)

=、+=、-= 、*=、/=、%= <<= 、>>=、&=、^=、|=   (赋值运算)

<、>、<=、>=、==、!=    (比较操作符)

&&、||    (逻辑与 和 逻辑或)

算术扩展:

$[] n=5;  echo $[$n+1] $(())        n=5;  echo $(($n+1)) (()) ((n+=1));  echo $n expr expr 4 + 5 注意+号两边要有空格      r=`expr 4 + 5` r=`expr 4 \* 5` let   // 内置命令  type let    let n=n+1    let “n = n + 1”    let “n=n+abc”    // abc 当做0

六、条件测试

任何一种测试中,都要有退出状态(返回值),退出状态为 0 表示命令成功或表达式为真,非0 则表示命令失败或表达式为假。

状态变量 $? 中保存命令退出状态的值

grep  study /etc/passwd; echo $?

grep   hello  /etc/passwd;echo  $?

(一)测试表达式的值

表达式测试包括字符串测试、整数测试和文件测试。

通常用 test 命令来测试表达式的值

x=5; y=10 test $x -gt $y echo $?

test 命令可以用 方括号 来代替(方括号前后要留空格)

x=5; y=10 [ $x -gt $y ]  echo $?

2.x 版本以上的 Bash 中可以用双方括号来测试表达式的值,此时可以使用通配符进行模式匹配。

name=Tom

[[ $name = [Tt]?? ]]  echo $?

(二)字符串测试   //字符串测试最好加上"  "

[ -z $str ]

如果字符串 str 长度为0,返回真

[ -n $str ]

如果字符串 str 长度不为0,返回真

[ $str1 ==  $str2 ]

两字符串相等

[ $str1 != $str2 ]

两字符串不等

name=Tom; [ -z $name ]; echo $?

name2=Andy; [ $name == $name2 ] ; echo $?

(三)整数测试 //操作符两边必须留空格!

[ int1 -eq int2 ]

int1等于int2

[ int1 -ne int2 ]

int1不等于int2

[ int1 -gt int2 ]

int1大于int2

[ int1 -ge int2 ]

int1大于或等于int2

[ int1 -lt int2 ]

int1小于int2

[ int1 -le int2 ]

int1小于或等于int2

x=1; [ $x -eq 1 ]; echo $?

整数测试也可以使用 let 命令或双圆括号:

相应的操作符为:== 、!= 、> 、>= 、< 、<=

x=1; let "$x == 1"; echo $?

x=1; (($x+1 >= 2 )); echo $? 

let 和 双圆括号中可以使用算术表达式,而方括号不能 let 和 双圆括号中,操作符两边可以不留空格

(四)逻辑测试

[ expr1 -a expr2 ]

逻辑与,都为真时,结果为真

[ expr1 -o expr2 ]

逻辑或,有一个为真时,结果为真

[ !expr ]

逻辑非

x=1; name=Tom; [ $x -eq 1 –a –n $name ]; echo $?

[ ( $x -eq 1 ) –a ( –n $name ) ]; echo $?  //error, 不能随便添加括号

可以使用模式的逻辑测试:

[[ pattern1 && pattern2 ]]

逻辑与

[[ pattern1 || pattern2 ]]

逻辑或

[[ !pattern ]]

逻辑非

x=1; name=Tom;

[[ $x -eq 1 && $name = To? ]]; echo $?

(五)检查空值

[ "$name" =  "" ]           [ ! "$name" ]                  [ "X${name}"  =  "X" ]

(六)文件测试

文件测试:文件是否存在,文件属性,访问权限等。更多文件测试符参见 man test

-f fname

fname 存在且是普通文件时,返回真 ( 即返回0 )

-L fname

fname 存在且是链接文件时,返回真

-d fname

fname 存在且是一个目录时,返回真

-e fname

fname(文件或目录)存在时,返回真

-s fname

fname 存在且大小大于0 时,返回真

-r fname

fname(文件或目录)存在且可读时,返回真

-w fname

fname(文件或目录)存在且可写时,返回真

-x fname

fname(文件或目录)存在且可执行时,返回真

(七)括号总结

${...}

获取变量值,${BASH:0:1} 可以代替 /

$(...)

命令替换

$[...]

让无类型的变量参与算术运算

$((...))

同上

((…))

算术运算

[ ... ]

条件测试,等价于test命令

[[ ... ]]

条件测试,支持模式匹配与通配符

七、条件与分支语句

(一)if条件语句

if expr1      #如果expr1为真(返回值为0)

then          #那么

   commands1  #执行语句块commands1

elif  expr2    #若expr1不真,而expr2为真

then          #那么

   commands2  #执行语句块commands2

 ... ... #可以有多个elif语句

else          # else最多只能有一个

   commands4  #执行语句块commands4

fi            #if语句必须以单词fi终止

几点说明:

 elif 可以有任意多个(0 个或多个); else 最多只能有一个(0 个或 1 个); if 语句必须以 fi 表示结束

 expr 通常为条件测试表达式;也可以是多个命令,以分号分隔,以最后一个命令的退出状态为条件值。

 commands 为可执行语句块,如果为空,需使用 shell 提供的空命令 “ : ”,即冒号。该命令不做任何事情,只返回一个退出状态 0

 if 语句可以嵌套使用。

(二)case 选择语句

case expr in # expr为表达式,关键词in不要忘!

pattern1) # 若expr与pattern1匹配,注意括号

   commands1 #  执行语句块commands1

   ;;        # 跳出case结构

pattern2) # 若expr与pattern2匹配

   commands2 #执行语句块commands2

   ;;        # 跳出case结构 ...... # 可以有任意多个模式匹配

*)        # 若expr与上面的模式都不匹配

   commands  # 执行语句块commands

   ;;        # 跳出case结构 esac # case语句必须以esac终止

几点说明:

表达式 expr 按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命令,然后退出 case。

 如果 expr 没有找到匹配的模式,则执行缺省值 “ *) ” 后面的命令块 ( 类似于 if  中的 else ); “ *) ” 可以不出现。

 所给的匹配模式 pattern 中可以含有通配符和“ | ”。

 每个命令块的最后必须有一个双分号,可以独占一行,或放在最后一个命令的后面。

八、循环语句

(一)for 循环

for variable  in  list

# 每一次循环,依次把列表list中的一个值赋给循环变量

do          #循环开始的标志

  commands  #循环变量每取一次值,循环体就执行一遍

done        #循环结束的标志

几点说明:

列表 list 可以是命令替换、变量名替换、字符串和文件名列表 ( 可包含通配符 )

list 里面的分隔符可以是空格、换行等等。

 for 循环执行的次数取决于列表 list 中单词的个数

 for 循环体中一般要出现循环变量,但也可以不出现

可以省略  in list ,此时使用“$@”

for ((exp1;exp2;exp3)  //类似于C语言的for 循环 do done

LIST="rootfs usr data data2" for d in $LIST; do  done

for d in seq_* ; do done

for i in ${arr[@]} ; do  done

for k in $( seq 1 $count ); do done

for file in $( ls $dir); do done

(二)while 和until循环

while expr  #执行expr

do #若expr的退出状态为0,进入循环,否则退出while

  commands  #循环体

done        #循环结束标志,返回循环顶部

eg.

#使用read命令读取一行数据   cat datafile.txt | while read myline   do        echo "LINE:"$myline   done  

while read name cn_name risk  #字段直接tab 分割,每行 \n 结束

do

    echo $name, $cn_name, $risk

done < $filename

read 命令默认的分隔符是空白符(如空格,tab等),我们也可以使用IFS(内部字段分隔符)指定的的字符作为分隔符;

需要注意的是多个空白被当做一个空白处理,当某一行中某个字段不存在,这样会导致读到的数据对应不到正确的变量

用 perl or python 读取一行数据时,需要去掉换行符,perl 用 chomp,python 用 strip('\n')

until expr  #执行expr

do #若expr的退出状态非0,进入循环,否则退出until

  commands  #循环体

done        #循环结束标志,返回循环顶部

(三)break和continue、exit和sleep

break  [n]

用于强行退出当前循环。

 如果是嵌套循环,则 break 命令后面可以跟一数字 n,表示退出第 n 重循环(最里面的为第一重循环)。

continue [n]

 用于忽略本次循环的剩余部分,回到循环的顶部,继续下一次循环。  如果是嵌套循环,continue 命令后面也可跟一数字 n,表示回到第 n 重循环的顶部。

exit n

exit 命令用于退出脚本或当前进程。n 是一个从 0 到 255 的整数,0 表示成功退出,非零表示遇到某种失败而非正常退出。该整数被保存在状态变量 $? 中。

sleep n  暂停 n 秒钟

(四)select循环和菜单

select variable in  list

do          #循环开始的标志

  commands  #循环变量每取一次值,循环体就执行一遍

done        #循环结束的标志

 select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入

 用户输入菜单列表中的某个数字,执行相应的命令

 用户输入被保存在内置变量 REPLY 中。

 select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环。

 select 经常和 case 联合使用

 与 for 循环类似,可以省略 in list ,此时使用位置参量

九、函数

 一个函数就是一个子程序,用于完成特定的任务,当有重复代码,或者一个任务只需要很少的修改就被重复几次执行时, 这时你应考虑使用函数。

local X   //  X 是局部变量

function function_name {

   commands

}

function_name() {

   commands

}

只需输入函数名即可调用该函数

 函数必须在调用之前定义

如果要调用其他文件的函数,可以在开头  . 文件名  //类似文件包含,也可以使用source。

这两个命令都以一个脚本为参数,该脚本将作为当前shell的环境执行,即不会启动一个新的子进程。所有在脚本中设置的变量将成为当前Shell的一部

分。同样的,当前脚本中设置的变量也将作为脚本的环境。

sh -x xx.sh 是在一个脚本中,调用另一个脚本执行,启动一个新的子进程,-x 会输出所有的执行信息。

脚本调用脚本,要对被调用脚本的执行返回值进行判断。参数同理,需要对脚本计算的参数进行合理判断,提前发现错误,避免走入不可控制的分支。

#!/bin/bash

fun2()

   echo "This is fun2."

   echo "Now exitingfun2."

}

fun2 #调用函数fun2

#! /bin/bash

func1()

{

        echo "the parameter's count:$#"

        echo "the firstparameter:$1"

        echo "the secondparameter:$2"

}

func1 a b

(一)字符串操作:

m 的取值从0 到${#var}-1

注:pattern,old中可以使用通配符。

${#var}

返回字符串变量 var的长度

${var:m}

返回${var}中从第m+1个字符到最后的部分

${var:m:len}

返回${var}中从第m+1个字符开始,长度为len的部分

${var#pattern}

删除${var}中开头部分与pattern匹配的最小部分

${var##pattern}

删除${var}中开头部分与pattern匹配的最大部分

${var%pattern}

删除${var}中结尾部分与pattern匹配的最小部分

${var%%pattern}

删除${var}中结尾部分与pattern匹配的最大部分

${var/old/new}

用new替换${var}中第一次出现的old

${var//old/new}

用new替换${var}中所有的old(全局替换)

字符串拼接:

value1=home

value2=${value1}"="

value3=${value1}${value2}

(二)随机数和 expr 命令

echo $RANDOM  // 生成随机数的特殊变量

expr:通用的表达式计算命令

表达式中参数与操作符必须以空格分开,表达式中的运算可以是算术运算,比较运算,字符串运算和逻辑运算。

expr 5 % 3

expr 5 \* 3 #乘法符号必须被转义

注意:目前比较少使用,可用$[ ... ]替换

(三)shift 命令

一般用于函数或者脚本程序参数处理,特别是参数多于10以上的时候 将所有参数变量向下移动一个位置,$2变成$1,$3变成$2,依次递进,但$0保持不变

例如:

while [ "$1" != "" ]

do

    echo $1

    shift

done

(四)eval 命令

eval arg1 [arg2] ... [argN]

将所有的参数连接成一个表达式,并计算或执行该表达式,参数中的任何变量都将被展开。

listpage="ls -l | more"

eval $listpage

(五)trap命令

trap command signal

command 一般情况下是Linux命令 ’ ’表示发生陷阱时为空指令,不做任何动作 ’-’表示发生陷阱时采用缺省指令 signal HUP(1) 挂起;一般因终端掉线或用户退出而引发 INT(2) 中断;一般因按下”Ctrl+C”组合键引发 QUIT(3) 退出;一般因按下”Ctrl+\”组合键引发 ABRT(6) 异常中止;一般因某些严重的执行错误而引发 ALRM(14) 闹钟;一般是超时时钟到来而引发 TREM(15) 中止;一般由系统在关机的时候发出

#!/bin/bash

#安装2、3号信号

#处理代码为"rm-ftmp$$; exit0"

trap "rm -ftmp$$; exit 0"  2 3

#生成文件,文件名为tmp+当前进程号

touch tmp$$

#睡眠60秒,以便向当前进程发送信号

sleep 60

(六)declare 命令

declare或typeset内建命令(它们是完全相同的)可以用来限定变量的属性.这是在某些编程语言中使用的定义类型不严格的方式。命令declare是bash版本2之后才有的。命令typeset也可以在ksh脚本中运行。

-r只读

declare -r var1

-i整数

declare -i number  # 脚本余下的部分会把"number"当作整数看待.

-a数组

declare -a indices

-f函数

declare -f

-x export

declare -x var3

-x var=$value

declare -x var3=373

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014-02-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档