Linux学习之路-Shell编程

Shell的编程

Bash是用得最广泛的shell,是大多数Linux 系统的缺省 shell。Bourne Again shell (bash), 正如它的名字所暗示的,是Bourne shell 的扩展。bash 与Bourne shell 完全向后兼容,并且在 Bourne shell 的基础上增加和增强了很多特性。bash 也包含了很多 C 和 Korn shell 里的优点。bash 有很灵活和强大的编程接口,同时又有很友好的用户界面。 下面具体来介绍bash。

Bash语法基本介绍

脚本的开头,必须以下面的行开始(必须方在文件的第一行):

#!/bin/bash

符号#!用来告诉系统它后面的参数是用来执行该文件的程序。当编辑好脚本时,如果要执行该脚本,有2种方式执行:

1.给脚本执行权限:

chmod +x filename 这样才能用./filename 来运行

2.直接用bash调用执行
         bash filename

注释

在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。

变量

在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明

根据类型又分为环境变量、本地变量、局部变量、位置变量、特殊变量(内置)

本地变量

varname=value:作用域为整个bash进程可以使用;

变量命名规范:

1. 只能含字母、数字和下划线,并且以字母和下划线开头

2. 最好不要跟系统已有的环境变量重名

3. 见名知意

局部变量

local varname=value:作用域为当前代码段;

环境变量:作用域为当前shell进程及其子进程,不能影响到其父进程;

export varname=value “导出”,如果变量已经定义可以只是用变量名 export     varname,即

1. export varname=value

2. varname=value

export varname

脚本在执行命令时会启动一个子shell环境变量:

位置变量

$1,$2,$3,……

cat first.sh test.txt hello

$1: first.sh

$2: test.txt

$3: hello

shift:踢掉参数

shift n:踢掉n个参数,默认踢掉一个参数

特殊变量:

$?:上一个命令执行状态的返回值:

程序执行可能有两种返回值:

1. 程序执行结果

2.程序状态返回吗(0-255)0则为执行正确,1-255  则执行出错(1,2,127系统预留);还可以使用exit n 自定义返回值

$#:获取当前shell命令行中参数的总个数

$*:获取当前shell的所有参数 “$1 $2 $3 …,受IFS控制

[email protected]:这个程序的所有参数 “$1″ “$2″ “$3″ “…”,不受IFS控制

$0  获取当前执行的shell脚本的文件名

$n  获取当前执行的shell脚本的第n个参数值,n=1..9

$$  获取当前shell的进程号(PID)

$!  执行上一个指令的PID

n  这些特殊变量在编程中是非常重要的,例如执行一个脚本testsh a1 a2 ,可以通过$1和$2获得a1和a2的值,$#可以用于判断是否有带参数,和参数个数。

n  还有一个shift [n]:轮替参数,可以把当前输入参数从左至右踢掉一个,可以用来方便的读取各个输入的参数

引用变量:
${varname},括号可以省略,但在某些时候必须使用,用来区分字符还是变量
例:${a}bc

撤销变量

unset varname

查看当前shell中的变量:

set  包括环境变量和本地变量

查看当前shell中的环境变量:

1. printenv    2. env    3. export

Bash还支持各种条件测试(数值测试、字符串测试、文件测试)

根据运行的命令的状态结果

有布尔型: “真”:成功, “假”:失败

例:

1 #!/bin/bash

2 if $(cat /etc/fstab &>/dev/null);then

3     echo $?"ok"

4 else

5     echo $?"false"

6 fi

如果cat /etc/fstab执行成功,条件则为真,输出0OK,执行失败输出1false

测试表达式

test EXPRESSION

[ EXPRESSION ]

[[ EXPRESSION ]]

例:

整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;

$A -gt $B:是否大于;是则为“真”,否则为“假”;

$A -ge $B: 是否大于等于;

$A -lt $B:是否小于;

$A -le $B: 是否小于等于;

$A -eq $B: 是否等于;

$A -ne $B:是否不等于;

例:

字符串测试:ASCII数值越大,字符比较时其值越大;

"$A" > "$B":是否大于;

"$A" < "$B":是否小于;

"$A" == "$B":是否等于;

"$A" != "$B":是否不等于;

-z "$A":是否为空;空则为“真”,否则为“假”

-n "$A":是否不空;不空则“真”,空则为“假”

注意:应该使用[[ EXPRESSION ]]

例:     1 #!/bin/bash

2 a="a"

3 b="b"

4

5 if [[ $a < $b ]];then

6     echo $?"ok"

7 else

8     echo $?"false"

9 fi

文件测试:测试文件的存在性以及属性;

-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: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的;

$file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的;

$file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;

例:

特殊设备:

u  /dev/null: 空,bit buckets,吞下所有数据,并直接丢弃;我们可以把一些不需要的信息丢弃,例如脚本中语句执行状态判断的时候

1 #!/bin/bash

2 if $(cat /etc/fstab &>/dev/null);then

3     echo $?"ok"

4 else

5     echo $?"false"

6 fi

cat /etc/fstab的输出全部丢弃了

u  /dev/zero:吐出一堆0;

提供输入,read命令:

语法:  read [options] VAR...

-p "PROMPT"

-t timeout

例:read –t 30 –p “请在30秒内输入你的名字:” names

停留30秒让用户输入名字,名字保存到变量names

命令引用:把执行的结果拿来使用

`COMMAND`, $(COMMAND)

可以使用`号或$(),建议使用$()更直观

例:times=$(echo “19:00”)

Bash也包含了for、if、case、等流程控制语句

判断语句:

if CONDITION; then

        if-true-分支

    fi

条件为真就执行里面的语句

例:if [ $a == “a”];then echo “ok”;fi

值得说明的是如果你将 if 和 then 简洁的写在一行里面,就必须在 then 前面加上分号,如:if [ expression ]; then ...。

if CONDITION; then

        if-true-分支1

    else

        if-false-分支2

    fi

条件为真执行分支1,否则执行分支2

例:if [ $a == “a”];then

echo “ok”

else

echo “false”

fi

case语句

    简洁版多分支if语句;           

    使用场景:判断某变量的值是否为多种情形中的一种时使用;

 

    语法:

        case $VARIABLE in

        PATTERN1)

           分支1

           ;;

        PATTERN2)

           分支2

           ;;

        PATTERN3)

           分支3

           ;;

        ...

        *)

           分支n

           ;;

        esac

 

        PATTERN可使用glob模式的通配符:

           *: 任意长度的任意字符;

           ?: 任意单个字符;

           []: 指定范围内的任意单个字符;

           a|b: 多选1;多条件判断

例:

#!/bin/bash

read -p "please input a char: " char

case $char in

[a-z])

echo "A character."

;;

[0-9])

echo "A digit."

;;

*)

echo "A special character."

;;

esac

注意每个分支语句后面跟;;

循环语句:

for VARIABLE in LIST; do

        循环体

done

n  LIST:是一个或多个空格或换行符分隔开的字符串组成;
把列表的每个字符串逐个赋值给VARIABLE表示的变量;

n  进入条件:列表非空;

n  退出条件:列表遍历结束

LIST的生成方法:

l  整数列表
     (a) {start..end}
     (b) $(seq [start [[step]] end)

l  直接给出列表

l  glob

l  命令生成

例:命令生成

1 #!/bin/bash

2 for i in $(ls);do

3     echo $i

4 done

例: 整数列表

1 #!/bin/bash

2 for i in {1..20};do

3     echo $i

4 done

------------

1 #!/bin/bash

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

3     echo $i

4 done

例:直接给出列表

1 #!/bin/bash

2 user1="aa"

3 user2="bb"

4

5 for i in $user1 $user2;do

6     echo $i

7 done

例:glob

1 #!/bin/bash

2 for i in /root/test/*;do

3     echo $i

4 done

while循环:

while CONDTION; do

循环体

控制变量的修正表达式

done

进入条件:当CONDITION为“真”;

退出条件:当CONDITION为“假”;

例:

1 #!/bin/bash

2 i=1

3 while [ $i -lt 20 ];do

4     echo $i

5     let i++

6 done

----------------------

打印99乘法表

1 #!/bin/bash

2 i=1

3 while [ $i -le 9 ];do

4   j=1

5      while [ $j -le $i ];do

6     echo -n -e "${j}x$i=$[$j*$i]\t"

7     let j++

8     done

9     echo -e "\n"

10     let i++

11 done

unitl循环:

until CONDITION; do

循环体

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

done

进入条件:当CONDITION为“假”时

退出条件:当CONDITION为“真”时

例:打印99乘法表

1 #!/bin/bash

2

3 i=1

4 j=1

5

6 until [ $i -gt 9 ];do

7     j=1

8     until [ $j -gt $i ];do

9         echo -e -n "${j}x$i=$[$j*$i]\t"

10

11     let j++

12     done

13     echo -e "\n"

14     let i++

15 done

循环控制:

continue [n]:提前结束本轮循环,而直接进入下一轮;

break [n]:提前结束循环;

例:

01.#!/bin/bash

02.

03.LIMIT=19  # 上限

04.

05.echo "Printing Numbers 1 through 20 (but not 3 and 11)."

06.

07.a=0

08.

09.while [ $a -le "$LIMIT" ]

10.do

11. a=$(($a+1))

12.

13. if [ "$a" -eq 3 ] || [ "$a" -eq 11 ]  # 除了3和11.

14. then

15.   continue      # 跳过本次循环剩余的语句.

16. fi

17.

18. echo -n "$a "   # 在$a等于3和11的时候,这句将不会执行.

19.done

20.

21.echo

22.exit 0

执行结果:

1.  Printing Numbers 1 through 20 (but not 3 and 11).

2.  1 2 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20

同样的程序改为break,说明break是程序跳出循环,之后的循环过程无法得到执行,break命令还可以带一个参数,一个不带参数的break命令只能退出最内层的循环,而break N可以退出N层循环。参数 N还是少用吧,比较绕。

01.#!/bin/bash

02.

03.LIMIT=19  # 上限

04.

05.echo "Printing Numbers 1 through 20 (but not 3 and 11)."

06.

07.a=0

08.

09.while [ $a -le "$LIMIT" ]

10.do

11. a=$(($a+1))

12.

13. if [ "$a" -eq 3 ] || [ "$a" -eq 11 ]  # 除了3和11.

14. then

15.   break      # 跳过本次循环剩余的语句.

16. fi

17.

18. echo -n "$a "   # 在$a等于3和11的时候,这句将不会执行.

19.done

20.

21.echo

22.exit 0

执行结果:

1.  Printing Numbers 1 through 20 (but not 3 and 11).

2.  1 2

循环的一些特殊用法:

死循环:

while true; do

循环体

if CONDTION; then

break

fi

done

until false; do

循环体

if CONDITION; then

break

fi

done

示例:每隔3秒钟查看当前系统上是否有名为“gentoo”的用户登录;

如果某次查看gentoo登录了,则显示gentoo已经登录;

如果未登录,就显示仍然未来,并显示这是已经是第多少次查看了;

#!/bin/bash

#

username=$1

declare -i count=0

while true; do

if who | grep "^$username" &> /dev/null; then

echo "$username is logged."

break

else

let count++

echo "$count $username is not login."

fi

sleep 3

done

while循环的特殊用法:

遍历文件的每一行:

while read VARIABLE; do

循环体

done < /PATH/FROM/SOME_FILE

示例:找出UID为偶数的所有用户,显示其用户名和ID号;

#!/bin/bash

#

while read line; do

userid=$(echo $line | cut -d: -f3)

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

echo $line | cut -d: -f1,3

fi

done < /etc/passwd

for循环的特殊用法(C语言风格):

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

循环体

done

expr1: 定义控制变量,并初始赋值;

expr2: 循环控制条件;

进入条件:控制条件为“真”

退出条件:控制条件为“假”

expr3: 修正控制变量

示例:求100以内所有正整数之和;

#!/bin/bash

#

declare -i sum=0

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

let sum+=$i

done

echo "Sum: $sum."

Bash也支持函数:function:

把一段具有独立功能代码封装在一起,并给予命名;后续用到时,可直接通过给定函数名来调用整体代码;可实现代码重用,模块化编程

函数格式:

function func () {

statementsreturn 1;

}

函数返回值

1、如果使用函数返回值,return只能返回一个整数(0~255),不能返回字符串,且返回值保存在$?变量中,不能直接赋值给其它变量例如,下面获得函数返回值的写法是错误的

function func () { return 3; }

i=`func`

2、如果return没有指定参数,则是最后一行脚本的退出状态值

3、如果要将函数返回值赋值给一个变量,有两种方式:

a)用$?赋值

funci=$?

b)在函数中,用echo打印返回值,再赋值

function func () { echo 3; }

i=`func`

函数参数

1、向函数传递的参数被当作位置参量来处理,在函数中是本地变量2、函数参数用$1, $2 ,..., $n来表示,但和通过命令行传递给脚本的参数不同。调用方式如下:

func param1 param2

函数中的变量

1、在一个shell中的变量无局部和全局之分,随用随声明,无作用域的概念。例如,在一个if...fi块中定义的变量,出了这个块的作用域仍然有效。所以我们尽量在函数中定义局部变量,使用local来定义

func() {

local count

echo $count

}

函数调用

1、使用function只是定义函数,要执行函数中的命令必须在脚本中或命令行上调用函数,例如: func param1 param2

a) 将函数单独放入一个脚本里,再在命令行上执行脚本(直接执行,或使用.,或source),是不会执行函数里的命令的

b) 将函数单独放入一个脚本,然后执行,相当于在执行该脚本的shell环境中定义了该函数

例如:下面的命令只是在shell环境中定义函数,并不会调用函数

./func_script.sh

source ./func_script.sh

2、函数可以递归:函数可以自己调用自己,调用次数没有限制

3、函数中使用exit命令退出整个脚本。

一些函数相关的命令

1、查看定义了哪些函数

declare -f

declare -F //只列出函数名

2、撤消函数定义unset func_name

3、将函数输出给子export -f func_name

脚本调试的一些技巧:

bash    -n: 检查脚本中的语法错误;

bash    -x:调试执行脚本;

时间: 2024-08-01 13:57:07

Linux学习之路-Shell编程的相关文章

Linux学习笔记(17) Shell编程之基础

1. 正则表达式 (1) 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配.grep.awk.sed等命令可以支持正则表达式:通配符用来匹配符合条件的文件名,通配符是完全匹配.ls.find.cp这些命令不支持正则表达式,所以只能使用shell自己的通配符来进行匹配了. (2) 基础正则表达式 元字符 作用 * 前一个字符匹配0次或任意多次 . 匹配除了换行符外任意一个字符 ^ 匹配行首,如:^hello会匹配以hello开头的行 $ 匹配行尾,如:hello$会匹配以hello结尾的

Linux学习笔记之shell编程基础

编程语言: 机器语言.汇编语言 .高级语言 静态语言:编译性语言 ,特点: 强类型(变量在使用前,必须先声明,甚至还需要初始化):事先转换成可执行文件.包含语言如: C .C++.JAVA.C# 动态语言:解释性语言 ,特点: 弱类型(变量用时声明,甚至不区分类型):边解释边执行.包含语言如: ASP.ASP.NET .PHP .SHELL .Python .PERL 编程能力: 面向过程 :Shell.C 面向对象:Python .Perl .JAVA .C++ Bash :变量 类型 环境变

Linux学习之路-Shell 工作原理

Shell 工作原理 什么是shell shell是命令语言.命令解释程序及程序设计语言的统称,是用户和Linux内核之间的接口程序,为用户提供使用操作系统的接口. shell的特性 shell的一个重要特性是它自身是一个解释型的程序设计语言,程序运行时由解释器全程参与运行过程,每次读取一行,运行一行.shell程序设计语言支持绝大多数在高级语言中能见到的程序元素,如函数.变量.数组和程序控制结构.shell编程语言简单易学,任何在提示符中能键入的命令都能放到一个可执行的shell程序中. sh

Linux学习篇之shell编程基础

设置环境变量: ① export 变量名=变量值   #设置环境变量 ② 变量名=变量值    #设置环境变量 export 变量名 set   #显示当前shell所有变量 env   #查看环境变量 unset 变量名  #删除变量 常用环境变量: PATH变量:系统查找命令的路径 echo $PATH    #查看PATH的值 PATH="$PATH":/root/sh   #将/root/sh目录加到PATH变量中(临时生效) PS1变量:命令提示符变量 当前语系查询: loc

Linux学习笔记(18) Shell编程之流程控制

1. if语句 (1) 单分支if条件语句 格式为: # 注意条件判断式两端的空格if [ 条件判断式 ];then 程序员 fi 或者 if[ 条件判断式 ] then 程序 fi 例:判断分区使用率 #!/bin/bash #获取根分区的使用率 rate=$(df -h | grep "/dev/sda5" | awk '{print $5}' | cut -d "%" -f 1) if [ $rate -ge 10 ] then echo "/dev

Linux学习8之Shell编程--基础正则表达式

1. 正则表达式与通配符 正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配的.grep.awk.sed等命令可以支持正则表达式. 通配符是用来匹配符合条件的文件名,通配符是完全匹配的.ls.find.cp等这些命令不支持正则表达式,所有只能使用Shell自己的通配符来进行匹配. 2. 基础正则表达式 原文地址:https://www.cnblogs.com/anchun7080/p/10311257.html

linux学习之路之脚本编程知识点

脚本编程知识点 1.获取变量中字符的长度 ${#VARNAME} 2.变量赋值 ${parameter:-word}:如果parameter为空或者未定义,则整个表达式为word:否则表达式值为parameter ${parameter:+word}:如果parameter为空或者未定义,则整个表达式为空:如果parameter有值,则整个表达式为word ${parameter:=word}:如果parameter为空或者未定义,则整个表达式值为parameter:否则整个表达式值为word

linux学习之路之bash及其特性

我们知道当我们用鼠标点击,或输入一个命令,系统就玩帮我们完成一个任务,那么当我们点击一个链接时,系统由是如何知道要去完成相应的操作呢?这是因为通过shell来完成的. 那么什么是shell呢? shell就是用户和操作系统之间的一个接口,通过这个接口shell接受来自用户的命令,并调用相应的应用程序来呼叫kernel来处理相应的工作. 在linux系统上面存放着多种类型的shell,这些shell存放在/etc/shells文件里,默认RedHat使用的shell为bash 下面介绍一些bash

linux学习之路之vim编辑器的使用

本章将介绍vim编辑器的使用 vim编辑器是vi编辑器的增强版 vim是一种全屏的编辑器,是一种模式化的编辑器,之所以称为模式化的编辑器,因为vim有多种模式. 接下来将介绍vim主要的三种模式: 编辑模式(也叫命令模式):在该模式下你可以完成字符串跳转,字符串删除,翻屏操作等操作 输入模式:在该模式下输入的任何字符都会保存在该文件中,作为文件的一部分 末行模式:在该模式下,可以实现字符串搜索,字符串替换等操作 vim编辑器的三种模式之间的相互转换 模式转换: 编辑模式-->输入模式 i:在当前