shell脚本编程

===============前言===============

bash编程属于解释性执行,解释器全程参与过程,每读取一行,执行一行,也可以理解成Linux上命令的堆砌,因为bash编程是调用机器上的命令程序文件进行程序编写

bash过程式编程:

顺序执行:逐行、逐个执行

选择执行:只执行其中一个分支(满足某个条件然后执行某个代码)

循环执行:一段代码重复执行0、1或多遍(执行多少次需要条件判断)


变量:可变化的量,存储在一个命名的内存空间中


bash环境:(区别在于生效范围)

本地变量:当前shell进程生效

环境变量:当前shell进程以及子进程生效

局部变量:某个函数执行过程(声明周期是函数开始执行至函数返回结束)

位置参数变量:$0 $1 $2 .....(传递给脚本的参数,在函数中引用传递给函数的参数)

 ./script_name   参数  参数  参数  ....

 $0(脚本本身)   $1   $2    $0   依次类推       


特殊变量:$? $# $* $@ $$

 $? 上一条命令的执行状态返回, 0代表成功   1-255代表失败

 $# 传递给脚本或者函数的参数个数

 $*和$@  所有参数本身

 $$ 脚本运行的当前进程ID


shift [N] 轮替 可以将$1踢掉,让$2向前一步编程$1,也可以一次踢掉多个,shift 2 ,则$3的变成$1了


变量类型(按值统计)

数值型:整数、浮点数

字符型:ASCII码

变量类型的作用:

存储空间 (字符串存储,跟整数存储格式是不同的,占用的空间也不相同)

运算 (字符加字符等于两个字符连接在一起而不是正常的数学运算)

存储格式 (不同类型的变量存储格式是不同的)

bash是属于弱类型编程语言,变量类型不严格区分,无需事先声明,默认存储机制是字符


================本地变量=================

格式:name=value

变量名只能包含字母数字和下划线,不能以数字开头

引用变量方法:${name},如果变量名后面没有紧跟其他字符的话,可以省略{},$name


引用:

'' 单引号,强引用,内部变量内容不会被替换为变量值

""  双引号,弱引用,内部变量会被替换成变量值

$()或者``  反单引号,命令替换,引用命令的执行结果


默认是字符型,如果想指定为整数型

1、declare  -i  name=value

2、let name=value


生命周期:创建 至 销毁

销毁分为自动销毁和手动销毁:自动销毁(shell进程终止),手动销毁(unset name)


查看所有本地变量:set


=================环境变量==================

把本地变量导出

export name=value

declare -x name=value

引用方法跟本地变量一样,强引用、弱引用、命令替换


销毁:unset name


查看所有环境变量:env printenv export


=================脚本基础知识点===================

脚本是一个文本文件,运行脚本的过程实际上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,而后由bash进程负责解析并运行此逻辑


启动脚本:

1、#bash script_file

2、给文件执行权限(chmod +x script_file),  ./script_file


shell脚本格式:顶格写#!/bin/bash

#代表注释,#后的内容不被执行


bash命令常用选项

-n 检查语法错误

-x 显示每一步执行过程,可以调试使用

$?返回结果

布尔型:

真:执行成功  0

假:执行失败  1-255


自定义脚本的状态结果

exit [n]   n可以自定义一个数字(失败代码)

注意事项:遇到exit则会立即终止当前shell进程,下文任何内容都不被执行


生成整数的方法

A、{start..end} 如: {1..100}  1到100的整数

B、$(seq [start [step]] end)

$(seq 1 100)  1到100的整数

$(seq 1 2 100)  1步进2到100,1 3 5 7 9 ...99  等于说1到100内的奇数

$(seq  100) 没有开始数默认从1开始,则为1到100内的整数


=================条件测试====================


特殊设备:

/dev/null 数据黑洞

/dev/zero 零发射器


bash之条件判断(选择性执行)

if/then case 两种语句


判断方法:

1、根据命令执行状态结果,命令执行ok则为真,否则为假

2、测试表达式(注意空格)

A、test EXPRESSION

B、[ EXPRESSION ]

C、[[  EXPRESSION ]]

整数测试 (隐含着数值大小比较,不要给变量引用加引号),使用单中括号[]

-gt  great than 大于,大于则为真,否则为假

-ge  great equal 大于等于,大于等于则为真,否则为假

-lt  less than 小于,小于为真,否则为假

-le  less equal 小于等于,小于等于为真,否则为假

-eq  equal 等于,等于为真,否则为假

-ne  not equal 不等于,不等于为真,否则为假


例如:  [ $A -gt $B ] 如果$A的值大于$B的值,条件为真,否则为假


字符串测试  (ASCII码数值越大,字符比较时也就越大)

"$A" > "$B"      是否大于,大于则为真,否则为假

"$A" < "$B"     是否小于,小于则为真,否则为假

"$A" == "$B"     是否等于,等于为真,否则为假

"$A" != "$B"      是否不等于,不等于为真,否则为假

"$A" =~ "$B"     左侧的内容是否能够被右侧的模式或内容所匹配,能匹配则为真,否则为假 ##必须使用双中括号 [[  ]] 

-z "$A" 判断$A的值是否为空,空为真,不空为假

-n  "$A" 判断$B的值是否不空,不空为真,空则为假

文件测试 (检测文件的存在性以及属性,使用[] ,如果变量名后面紧跟其他字母则必须添加双引号"",或使用${}

-e $file  是否存在,存在为真,否则为假

-a $file 同上

-f $file  文件是普通文件且存在则为真,否则为假

-d $file  文件是目录文件且存在则为真,否则为假

-h $file  文件是符号链接文件存在则为真,否则为假

-L $file  同上

-b $file  文件是块设备且存在则为真,否则为假

-c $file  文件是字符设备且存在则为真,否则为假

-S $file  文件是套接字文件且存在则为真,否则为假

-p $file  文件是管道文件且存在则为真,否则为假

-r $file  当前用户对文件是否拥有读权限,有为真

-w $file  当前用户对文件是否拥有写权限,有为真

-x $file  当前用户对文件是否拥有执行权限,有为真

-u $file 文件是否拥有SUID权限,是为真

-g $file 文件是否拥有SGID权限,是为真

-k $file 文件是否拥有sticky权限,是为真

-O $file 当前用户是否是文件的属主,有为真

-G $file 当前用户是否是文件的属组,有为真

$file1 -nt $file2 fiel1是否新于file2,是则为真 (比较时间戳,newer than)

$file1 -ot $file2   file1是否旧于file2,是则为真 (older than)

  $file1 -ef $file2   file1跟file2是否属于同一个文件的硬连接,相同的inode号,是则为真

  


中括号 [] 内的每个组建都需要用空格隔开

中括号内的变量,最好用双引号引起来

中括号内的常量,最好用单引号或双引号来设置  

  

================if语句===================

if属于选择性执行,另外case也是


if语句格式:


如果条件为真,则执行分支中的代码,否则不执行


if CONDITION;then

 if-true-分支

fi



如果条件为真,执行true分支的代码,否则执行false分支中的代码


if CONDITION;then

 if-true-分支

else

 if-false-分支

fi


如果有多个条件判断,可以使用elif


if CONDITION1;then

 if-CONDITION1-true-分支

elif CONDITION2;then

 if-CONDITION2-true-分支

......


else ##所有条件都不满足,也不想执行任何代码,可以省略else

if-ALL-false-分支

fi



举个例子:

[root@www tmp]# cat test1 

#!/bin/bash

dir1=/var/

dir2=/usr/

if [ $dir1 == $dir2 ];then

  echo "$dir1 and $dir2 is same"

fi


[root@www tmp]# bash -x test1

+ dir1=/var/

+ dir2=/usr/

+ '[' /var/ == /usr/ ']'

[root@www tmp]# 

可以看出单分支语句,条件为真则执行,否则不执行


添加一点东西:


[root@www tmp]# cat test1 

#!/bin/bash

dir1=/var/

dir2=/usr/

if [ $dir1 == $dir2 ];then

  echo "$dir1 and $dir2 is same"

else

  echo "$dir1 $dir2 is different"

fi


[root@www tmp]# bash -x test1

+ dir1=/var/

+ dir2=/usr/

+ '[' /var/ == /usr/ ']'

+ echo '/var/ /usr/ is different'

/var/ /usr/ is different

[root@www tmp]# 

给出了条件为真,然后怎样,为假时又怎样


例如:给出一个路径,判断是否存在,存在就提示目录存在,不存则创建并返回已创建完成


[root@www tmp]# cat test1.sh 

#!/bin/bash

read -p "give a directory " -t 10 dir  ##read  跟用户交互 -p 提示信息  -t 超时时间为10秒,dir是自定义的变量名

if [ -z $dir ];then ##判断是否键入内容

  echo "must input a directory"

  exit 1

fi


if [ -d $dir ];then      ##判断是否是一目前且存在

  echo "$dir is existed "

else

  mkdir -p $dir 

  if [ -d $dir ];then

     echo "$dir is creat ok"

   fi

fi


[root@www tmp]# bash -x test1.sh 

+ read -p 'give a directory ' -t 10 dir

give a directory ##如果不给出一个目录

+ '[' -z ']'

+ echo 'must give a directory'

must give a directory

+ exit 1            ##遇到exit则退出脚本,后面的代码统统不执行


[root@www tmp]# bash -x test1.sh 

+ read -p 'give a directory ' -t 10 dir

give a directory /tmp/a/b/c/d #给出一个目录,如果不存在则创建

+ '[' -z /tmp/a/b/c/d ']'

+ '[' -d /tmp/a/b/c/d ']'

+ mkdir -p /tmp/a/b/c/d

+ '[' -d /tmp/a/b/c/d ']'

+ echo '/tmp/a/b/c/d is creat ok' 提示创建OK,mkdir -p,如果父目录不存在子目录创建是出错的,所以加了-p

/tmp/a/b/c/d is creat ok


elif举例,给出一个文件,判断文件类型


[root@www tmp]# cat test3.sh 

#!/bin/bash

if [ $# -lt 1 ];then ##脚本的参数小于1,则给给出提示并退出 错误为1(exit 1)

  echo "please give a filename"

  exit 1

fi


if [ -d $1 ];then

  echo "$1 is a dir"

elif [ -f $1 ];then

  echo "$1 is z regular file"

elif [ -b $1 ];then

  echo " $1 is a block file"

elif [ -c $1 ];then

  echo "$1 is a character file"

else

  echo "$1 is not exist or unknow type"

fi


[root@www tmp]# bash -x test3.sh   #执行,并且显示步骤

+ '[' 0 -lt 1 ']'                 #没有给出参数,给出提示信息,然后退出

+ echo 'please give a filename'

please give a filename

+ exit 1

[root@www tmp]# bash -x test3.sh /dev/cdrom 

+ '[' 1 -lt 1 ']'

+ '[' -d /dev/cdrom ']'

+ '[' -f /dev/cdrom ']'

+ '[' -b /dev/cdrom ']'

+ echo ' /dev/cdrom is a block fi le'

 /dev/cdrom is a block file

 

 

[root@www tmp]# bash -x shift.sh 1 2 3 4 #shift轮替

+ echo 1 #正常显示,1本来就是$1的位置

1

+ shift   #轮替,讲1 踢走,2变成$1位置

+ echo 2

2

+ shift 2 #踢走两个,2 3 踢走,于是4变成$1位置

+ echo 4


不过shift用在那种情况下?


举例:给出两个数字,判断孰大孰小

#!/bin/bash

read -p "please input two number: " -t 15 num1 num2

if [ -z $num1 ];then

  echo "SB two number ? "

  exit 1

elif [ -z $num2 ];then

  echo " two number? SB "

  exit 2                      ##在这个例子中就没有给出else

fi


if [ $num1 -eq $num2 ];then

  echo "${num1}=${num2}"

elif [ $num1 -gt $num2 ];then

   echo "${num1}>${num2}"

else

   echo "${num1}<${num2}"

fi


[root@www tmp]# bash -x test4.sh 

+ read -p 'please input two number: ' -t 15 num1 num2

please input two number: 4453545 13212111

+ '[' -z 4453545 ']'

+ '[' -z 13212111 ']'

+ '[' 4453545 -eq 13212111 ']'

+ '[' 4453545 -gt 13212111 ']'

+ echo '4453545<13212111'

4453545<13212111


==================循环语句之for=================

循环语句除了for以外还有while until


for格式:

for VARIABLE in LIST;do  ##需要牢记其格式

  循环体

done


VARIABLE是一个自定义的变量名

LIST是由空格或换行符隔开的字符串组成,把LIST表中没一个字符串分别依次赋值给VARIABLE


进入循环条件:VARIABLE得到LIST的赋值,不为空

退出循环条件:LIST表中遍历完


VARIABLE可以自定义起个名字

LIST可有以下几种形式:

1、整数列表

{start..end}

$(seq [start [step]] end)

2、直接给出列表

3、glob

4、命令生成



先说明下算术运算:

算术运算符号:+ - * / % **   加 减 乘 除 取余 次方

运算格式:

$[$A+$B]

$(($A+$B))

let VARIABLE=$A+$B

VARIABLE=$(expr %A + $B)   #注意+空格隔开


sum=$[$sum+$i]  等于$sum+=$i  同理

sum=$[$sum-$i]  等于$sum-=$i

sum=$[$sum*$i]  等于$sum*=$i

sum=$[$sum/$i]  等于$sum/=$i

sum=$[$sum%$1]  等于$sum%=$i

整数列表举例

1-100之间的所有正整数相加

#!/bin/bash

declare -i sum=0

for i in {1..100};do

 let sum=$sum+$i          ##可以写成$sum+=$i

done

echo $sum


1-100之间所有偶数相加

#!/bin/bash

declare -i sum=0

for i in $(seq 0 2 100);do

   sum+=$i

done

echo $sum


1-100之间所有奇数相加

#!/bin/bash

declare -i sum=0

for  i in $(seq 1 2 100);do

   sum+=$i

done 

echo $sum

还可以这么写:


#!/bin/bash

declare -i sum=0

for i in {1..100};do

  if [ $[$i%2] -eq 1 ];then    #先给出范围,然后使用if判断出奇数来(奇数取余2结果为1,偶数取余结果为0)

    sum+=$i

   fi

done

echo $sum



==============组合测试条件==================

条件之间的逻辑运算:与 或 非

与:多个条件同时满足

或:多个条件满足其一

非:对指定的条件取反

表达式组合、命令组合

表达式组合

与:` CONDITION1 -a CONDITION2 `

或:` CONDITION1 -o CONDITION2 `

非:[ ! CONDITION ]

命令组合

   与:COMMAND1 && COMMAND2 

   或:COMMAND1 || COMMAND2

   非:! COMAND


短路操作符 

如果左侧为真,则运行右侧的命令

如果左侧为假,右侧命令在不运行(结果一定为假)

true && true = true

true && false =false

false && false =false

false && true = false

如果左侧为真,右侧则不运行(结果一定为真)

如果左侧为假,右侧则运行

true || true = true

true || false = true

false || true = true

false || false = false

==============if、for举例================

例如,如果主机名包含local,或者为空,则修改成www.test.com(把老师原题目改了下)

#!/bin/bash

hostname=$(hostname)

if [ -z $hostname ] || [[ "$hostname" =~ "local" ]] ;then    ##两个判断不能放在同一个中括号里,所以把两个分开来写

 hostname www.test.com

fi

hostname


有个地方需要格外注意,如果使用正则表达,则不能使用双引号引起来,否则正则就没有用了,当成字符串了,所以 =~  "local"  的双引号可以去掉


[root@www tmp]# bash  -x test5.sh 

++ hostname

+ hostname=localhost.localdomain

+ '[' -z localhost.localdomain ']'

+ [[ localhost.localdomain =~ local ]]

+ hostname www.test.com

+ hostname

www.test.com


在做这一题的时候本想把两个条件测试写成这样的格式 [[ -z EXPR1  -o  EXPR2 =~ local ]],然后一直报语法错误,单中括号、还有双引号反复试了下都不行[[  $hostname =~ local  ]] 语法ok,[[ -z $hostname ]]  也OK,但是放到一起使用  -o  连接一起就不行,最后把两个判断分别用中括号括起来,中间用命令组合中的--》 或--》  ||符号连接,结果OK

在做一个事例,要求:

传递给两个文件给脚本

显示两个文件中空白行数较多的文件及其空白行的个数

显示两个文件中的总行数较多的文件及其总行数



#!/bin/bash

read -p "PLS input 2 regular file: "  file1 file2


#if  [ -z "$file1" -o -z "$file2" ] ;then

# echo "SB 1  ......."

#     exit 1

#fi

判断两个变量是否为空,在这个地方犯了一个错误,$file1 $file2 ,没有加双引号导致给出一个参数也能继续后面的代码

#if [ -z $file1 ];then

#  echo "SB 1 ..."

#  exit 1

#elif [ -z $file2 ];then

#  echo "sb1 ...."

#  exit 1

#fi

效果同上,可以看出else是可以省略不要的

if  [ -z "$file1" ] || [ -z "$file2" ] ;then

 echo "SB 1  ......."

     exit 1

fi

效果同上,这种情况下$file1和$file2的双引号是可以省略的


if [ ! -f "$file1" -o ! -f "$file2" ];then


echo "SB 2 ........"

        exit 2

fi



if是逐条匹配,第一条匹配不到就找下一条匹配,所有找不到就执行else的默认代码(如果有else的话)

sp1=$(grep -c "^$" $file1)

sp2=$(grep -c "^$" $file2)

wc1=$(wc -l $file1|cut -d ' '  -f1)

wc2=$(wc -l $file2|cut -d ' '  -f1)


if [ $sp1 -eq $sp2 ];then

   echo "$file1 has $sp1 spaces = $file2 has $sp2 spaces"

elif [ $sp1 -gt $sp2 ];then

    echo "$file1 has $sp1 spaces > $file2 has $sp2 spaces"

else

    echo $"$file1 has $sp1 spaces < $file2 has $sp2 spaces"

fi



if [ $wc1 -eq $wc2 ];then

  echo "$file1 = $file2"

elif [ $wc1 -gt $wc2 ];then

 echo "$file1 has $wc1 lines > $file2 has $wc1 lines "

else

 echo "$file1 has $wc1 lines < $file2 has $wc1 lines"

fi



在举个for循环的例子

九九乘法表


#!/bin/bash


for x in $(seq 1 9);do

  for y in $(seq 1 "$x");do

    z=$[$x*$y]

  echo -n -e  "${y}*${x}=${z}\t"

  done

echo 如果不用echo显示一行隔开,所有的都连在一起了

done



echo 中

-n  不换行

-e  配合后面的\t   制表符


看的时候不能竖着看,横着看,就顺多了

例如:1*5=5 2*5=10 3*5=15 4*5=20 5*5=25   这一行,被乘数是5,乘数分别是1、2、3、4、5,每一行的乘数的取值范围是1到被乘数之间的整数



1*1=1

1*2=2 2*2=4

1*3=3 2*3=6  3*3=9

1*4=4 2*4=8  3*4=12 4*4=16

1*5=5 2*5=10 3*5=15 4*5=20 5*5=25

1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36

1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49

1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64

1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81



==============case语法==============

简洁版的多分支if语句

判断某变量的值是否为多种情形中的一种


语法格式:

case $VARABLE in                ##if CONDITION;then     .... 

PATTERN1)

  分支1

  ;;

PATTERN2)

  分支2

  ;;

  

  ……

*) ##相当于if的else  ,*表示通配

  分支n

  ;;

esac                  ##case 倒置过来写  


PATTERN可使用glob模式的通配符

*  任意长度的任意字符

?  单个任意字符

[]  范围取值

| 或   a|b   a或者b,二选一


示例:

脚本可以接受四个参数

start:创建文件/var/lock/subsys/SCRIPT_NAME

stop:删除此文件

restart:删除重新创建

status:如果文件存在,显示running,否则显示stopped


#!/bin/bash

dir=/var/lock/subsys/

fname=${dir}$(basename $0)

case $1 in 

start)

touch $fname && echo "$fname is start ok " || echo "$fname start failed"  ##创建$fname,成功显示启动成功,否则显示启动失败

;;

stop)

rm -rf $fname && echo "$fname stop ok" || echo "$fname stop failed"

;;

restart)

rm -rf $fname && touch $fname 

echo "$fname restart ok"

;;

status)

  if [ -f $fname ];then

     echo "$fname is running..."

  else

      echo "$fname is stopped"

  fi

;;

*)

echo "Usage $0 start|stop|restart|status "

esac


=============until、while语法==============

until语法:

until CONDITION;do

循环体

循环控制变量的修正表达式

done


语法跟while非常像

while语法

while CONDITION;do

循环体

循环控制变量的修正表达式

done


二者的区别在于进入和退出条件

until:

进入条件   当CONDITION为假

退出条件   当CONDITION为真


while:

进入条件  当CONDITION为真

退出条件  当CONDITION为假


while举例:   ##1到100的和

#!/bin/bash

declare -i sum=0

declare -i j=0

while [ $j -le 100 ];do   ##条件为真进入循环

  let sum+=$j

  let j++

done

echo $sum


until举例:

#!/bin/bash

declare -i sum=0

declare -i j=0

until [ $j -gt 100 ];do   ##条件为假进入循环

  let sum+=$j

  let j++

done

echo $sum



============循环控制=============

continue  跳过本次循环,进入下个循环

break     结束循环


死循环:

while  true;do

  循环体

  if CONDITION;then   #不能一直循环下去,设定一个条件,满足后就结束循环

    break

  fi

done


until false;do

  循环体

  if CONDITION;then

     break

  fi

done   




==========while、for特殊用法=============

while循环,从其他文本中读取,文本中的内容被赋予VARIABLE

while  read VARIABLE;do

循环体

done < /path/from/some_file



for ((expr1;expr2;expr3));do

循环体

done

expr1  定义一个变量并复制

expr2  循环控制条件

     进入条件  控制条件为真

     退出条件  控制条件为假

expr3  修正控制变量     


例如,计算1到100之和

#!/bin/bash

declare  -i sum=0

for ((i=1;$i<=100;i++));do

let sum+=$i

done

echo $sum


=============function==================


功能:

代码重用

模块化编程


定义方法:

function f_name {

函数体

}


f_name() {

函数体

}


函数的使用方法:

先定义:编写函数代码

后调用:给出函数名,还可以按需传递参数


调用方法:

f_name [ arg1,arg2,....]   #可直接写出函数名进行调用,也可以加参数



函数状态返回值

0:成功

1-255:失败

就像for、if等遇到exit一样,函数遇到return则退出循环






===============模块化编程=================

函数文件和脚本文件分开

脚本中使用 . function   或者source function 载入函数

变量的作用域:                      ####本地变量,则作用在整个脚本中,尽量避免function中的变量跟脚本中的变量冲突

local  VARIABLE=value

存活时间:函数执行开始,至函数返回结束,作用与函数内部


[ -r fname ] && . fname  判断fname文件存在而且可读,那么就载入进来




例如:  判断用户id的奇偶性

[root@www f-test]# cat username function idcheck.sh   ##同个目录下三个文件,username填写用户名,function定义函数,idcheck脚本内容

username=wkp  ##username文件内容


idcheck() {              ##function文件内容

if ! id $username &> /dev/null ;then

    echo "$username is not exist"

    return 1

fi 

num=$(id -u $username)

[ $[$num%2] -eq 0 ] && echo "$username id oushu" || echo "$username id qishu"

}



#!/bin/bash                 ##idcheck.sh文件内容

[ -r username ] && . username         ##判断username文件,并载入 

[ -r function ] && source function    ##判断function文件,并载入

idcheck



[root@www f-test]# bash -x idcheck.sh          ##执行 

+ '[' -r username ']'

+ . username

++ username=wkp

+ '[' -r function ']'

+ source function

+ idcheck

+ id wkp

++ id -u wkp

+ num=783

+ '[' 1 -eq 0 ']'

+ echo 'wkp id qishu'

wkp id qishu


[root@www f-test]# vi username    ##做一个错误的判断

[root@www f-test]# cat username 

username=ZZZZZZZZZ

[root@www f-test]# bash -x idcheck.sh 

+ '[' -r username ']'

+ . username

++ username=ZZZZZZZZZ

+ '[' -r function ']'

+ source function

+ idcheck

+ id ZZZZZZZZZ

+ echo 'ZZZZZZZZZ is not existed'

ZZZZZZZZZ is not existed

+ return 1

[root@www f-test]# 

===============练习部分================

写一个脚本:如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型


#!/bin/bash

if [ $# -lt 1 ];then             ##脚本参数不能小于1,否则退出执行

  echo "input a path "

  exit 1

fi


if [ -e $1 ];then        ##给出的路径存在则显示类型

  echo "$1 is exist"

  file $1

else

 mkdir -pv $1              ##否则创建路径

fi


[root@www tmp]# ./sc1.sh /etc/fstab    ##存在的

/etc/fstab is exist

/etc/fstab: ASCII text


[root@www tmp]# ./sc1.sh /tmp/a/b/c     ##不存在

mkdir: created directory `/tmp/a'

mkdir: created directory `/tmp/a/b'

mkdir: created directory `/tmp/a/b/c'



写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:脚本参数,命令交互;(使用read,依然如此简单)


#!/bin/bash

read -p "PLZ input two number: " -t 20  num1 num2

if [ -z "$num1" -o -z "$num2" ];then

  echo "error number"

  exit 1

fi


if [ $num1 -eq $num2 ];then

  echo "$num1 = $num2"

fi

if [ $num1 -gt $num2 ];then

  echo "$num1 > $num2"

else

  echo "$num1 < $num2"

fi


[root@www tmp]# ./num.sh 

PLZ input two number: 

error number

[root@www tmp]# ./num.sh 

PLZ input two number: 666 999

666 < 999

[root@www tmp]# 


求100以内所有奇数之和(至少用3种方法。是的这是我们的作业^_^)

#!/bin/bash

declare  -i sum=0

for ((i=1;$i<=100;i++));do      ##for的特殊用法:定义变量  取值  修正值

  if ! [ $[$i%2] -eq 0 ];then    ##取余为0的是偶数,!则是取反

        let sum+=$i

   fi

done

echo $sum



#!/bin/bash

declare -i sum=0

declare -i i=0

while [ $i -le 99 ];do      ##小于等于99,如果写成小于等于100,结果或多出101

  let i++                  ##修正变量值放在前面,否则i=0 然后continue,然后循环开始还是i=0,不能继续下去成了一个死循环

    if [ $[$i%2] -eq 0 ];then

        continue

    else

        let sum+=$i

     fi

done

echo $sum



#!/bin/bash

#

declare -i sum=0

for i in $(seq 1 2 100);do   ##没错就是这么简单,直接定义所有奇数,不判断

   let sum+=$i

done

echo $sum


写一个脚本实现如下功能:

(1) 传递两个文本文件路径给脚本;

(2) 显示两个文件中空白行数较多的文件及其空白行的个数;

(3) 显示两个文件中总行数较多的文件及其总行数;


#!/bin/bash

if [ -z "$1" -o -z "$2" ];then

  echo "input two files..."

  exit 1

fi


if ! [ -f $1 -o -f $2 ];then

   echo "error file..."

   exit 2

fi


declare -i space1=$(grep -c "^$" $1)

declare -i space2=$(grep -c "^$" $2)

declare -i wc1=$(wc -l $1 | cut -d ' ' -f1)

declare -i wc2=$(wc -l $2 | cut -d ' ' -f1)


if [ $space1 -eq $space2 ];then

  echo "$1 has space $space1 = $2 has space $space2"

fi

if [ $space1 -gt $space2 ];then

  echo "$1 has space $space1 > $2 has space $space2"

else

  echo "$1 has space $space1 < $2 hsa space $space2"

fi

if [ $wc1 -eq $wc2 ];then

  echo "$1 has $wc1 lines = $2 has $wc2 lines"

fi

if [ $wc1 -gt $wc2 ];then

  echo "$1 has $wc1 lines > $2 has $wc2 lines"

else

  echo "$1 has $wc1 lines < $2 has $wc2 lines"

fi



[root@www tmp]# ./file.sh  /etc/fstab 

input two files...

[root@www tmp]# ./file.sh  a b

error file...

[root@www tmp]# ./file.sh  /etc/fstab /etc/inittab

/etc/fstab has space 1 > /etc/inittab has space 0

/etc/fstab has 17 lines < /etc/inittab has 26 lines


写一个脚本

(1) 提示用户输入一个字符串;

(2) 判断:

如果输入的是quit,则退出脚本;

否则,则显示其输入的字符串内容;


#!/bin/bash

while true ; do

read -p "input a word:" wd

if [ -z "$wd" ];then

 echo "f**K! input a word ..."

elif [ "$wd" == quit ];then

  break

else

  echo "$wd"

fi

done


执行结果:

[root@www tmp]# bash -x read.sh 

+ true

+ read -p 'input a word:' wd

input a word:

+ '[' -z '' ']'

+ echo 'f**K! input a word ...'

f**K! input a word ...

+ true

+ read -p 'input a word:' wd

input a word:aaaaa

+ '[' -z aaaaa ']'

+ '[' aaaaa == quit ']'

+ echo aaaaa

aaaaa

+ true

+ read -p 'input a word:' wd

input a word:quit

+ '[' -z quit ']'

+ '[' quit == quit ']'

+ break



写一个脚本,打印2^n表;n等于一个用户输入的值;(不好意思,我调皮了)

#!/bin/bash

read -p "input a number: " num

if [ -z $num ] || [ "$num" -lt 0 ];then

  echo "error number!"

  exit 1

fi


for i in $(seq 0 $num);do

  echo "2^$i=$[2**$i]"

done


[root@localhost tmp]# bash 2n.sh 

input a number: 4

2^0=1

2^1=2

2^2=4

2^3=8

2^4=16


写一个脚本,写这么几个函数:

函数1、实现给定的两个数值的之和;

函数2、取给定两个数值的最大公约数;

函数3、取给定两个数值的最小公倍数;

关于函数的选定、两个数值的大小都将通过交互式输入来提供。


#!/bin/bash

#############Usage######################

usage() {

  if [ -z $num1 ] || [ -z $num2 ];then

    echo "Error: $(basename $0) number1 number2"

    exit 1

  elif ! [[ "$num1" =~ ^[1-9]+$ ]];then

    echo "Error,please input a right number"

    exit 2

  elif ! [[ "$num2" =~ ^[1-9]+$ ]];then

    echo "Error,please input a right number"

    exit 2

  fi

}

############gongbeishu###################

gongyueshu() {


if [ $num1 -eq $num2 ];then

  echo "gongyueshu: $num1 gongbeishu: $num1"

  exit

fi

####如果给出的两个数字相同,那么他们的最大公约数和最小公倍数就是它们自己本身

if [ $num1 -gt $num2 ];then

  great=$num1

  small=$num2

else

   great=$num2

   small=$num1

fi

######如果两个数字不相同,判断出哪个数大,哪个数小,下面的取值需要用到

#####取值范围是1到最小数之间的,然后大数和小数分别取余,最后一次二者同为0的时候,就是他们的最大公约数(let i++很重要)

for i in $(seq 1 $small);do

  greattmp=$(expr $great % $i)     ###大数取余

  smalltmp=$(expr $small % $i)     ###小数取余

  if [ $greattmp -eq 0 ] && [ $smalltmp -eq 0 ];then   ##取余同时为0

     gongyue=$i                                        ##最大公约数

  fi

  let i++                                              ##非常重要

done

#echo $gongyue

}

################gongbeishu#################

gongbeishu() {

gongyueshu        ##载入公约数函数,下面用得到

gongbei=$[$small/$gongyue*$great]     ##最小公倍数=小数/最大公约数*大数

#echo $gongbei

}

##########################################

qiuhe() {

  sum=$[$num1+$num2]

}

######################################

read -p "input two number: " num1 num2   ##通过交互获取num1 num2


usage  ##调用usage函数


qiuhe   ##调用求和函数

echo "$num1 + $num2 = $sum"

gongyueshu   ##调用公约数函数

echo "$num1 $num2 最大公约数: $gongyue"

gongbeishu   ##调用公倍数函数

echo "$num1 $num2 最小公倍数: $gongbei"


[root@localhost tmp]# ./yuebei.sh 7 9

7 + 9 = 16

7 9 最大公约数: 1

7 9 最小公倍数: 63