bash基础


前言

在Linux学习过程中,我们无可避免的会碰到一个既让人喜欢,又令人头疼的神奇的东西——bash编程,即shell脚本。那么什么是shell脚本呢?shell是一个命令语言解释器,而shell脚本则是Linux命令的集合,按照预设的顺序依次解释执行,来完成特定的、较复杂的系统管理任务,类似于Windows中的批处理文件。本文带来的是bash编程的基础语法讲解。

bash编程之变量

bash变量类别

本地变量:只对当前shell进程有效的变量,对其它shell进程无效,包当前shell进程的子进程

1

VAR_NAME=VALUE

变量赋值:向变量的存储空间保存数据

变量引用:${VAR_NAME}

1

2

"":弱引用,里面的变量会被替换

'':强引用,里面的所有字符都是字面量,直接输出

环境变量:对当前shell进程及其子shell有效,对其它的shell进程无效

1

2

3

4

定义:export VAR_NAME=VALUE

导出:export VAR_NAME

撤消变量:unset VAR_NAME

只读变量:readonly VAR_NAME

局部变量:对shell脚本中某代码片断有效,通常用于函数本地

1

local VAR_NAME=VALUE

位置变量:用来接受变量指定位置的参数

1

$1,$2...,${10}

特殊变量:shell对一些参数做特殊处理,这些参数只能被引用而不能被赋值

1

2

3

4

5

6

7

$#  传递到脚本的参数个数

$*  显示所有向脚本传递的参数                  #与位置变量不同,此选项参数可超过9个

$$  获取当前shell的进程号

$!  执行上一个指令的进程号

$?  获取执行的上一个指令的返回值              #0为执行成功,非零为执行失败

$-  显示shell使用的当前选项,与set命令功能相同

$@  与$*相同,但是使用时加引号,并在引号中返回每个参数

查看变量:

1

2

set:查看当前shell进程中的所有变量

exportprintenvenv:查看当前shell进程中的所有环境变量

变量命名:

1、不能使用程序中的关键字(保留字)

2、只能使用数字、字母和下划线,且不能以数字开头

3、要见名知义

变量类型:

数值型:精确数值(整数),近似数值(浮点型)

字符型:char,string

布尔型:true, false

类型转换:显式转换,隐式转换

bash的配置文件:

profile类:为交互式登录的用户提供配置

全局:/etc/profile、/etc/profile.d/*.sh

用户:~/.bash_profile

bashrc类:为非交互式的用户提供配置

全局:/etc/bashrc

用户:~/.bashrc

功能:设定本地变量,定义命令别名

bash编程之编写格式及执行方式

编写格式:

shell脚本第一行必须顶格写,用shebang定义指定的解释器来解释该脚本。

1

#!/bin/bash       #!即为shebang

其它的以#开头的行均为注释,会被解释器忽略,可用来注释脚本用途及版本,方便使用管理。

执行方式:

bash编程属于面向过程编程,执行方式如下:

顺序执行:按命令先后顺寻依次执行

选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支

循环执行:将同一段代码反复执行多次,因此,循环必须有退出条件;否则,则陷入死循环

bash执行选项:

1

2

bash -n SHELLNAME  #语法测试,测试是否存在语法错误

bash -x SHELLNAME  #模拟单步执行,显示每一步执行过程

bash之算数运算与逻辑运算

算数运算

定义整型变量:

1

2

let VAR_NAME=INTEGER_VALUE            #例如:let a=3

declare -i VAR_NAME=INTEGER_VALUE     #declare -i a=3

实现算术运算的方式:

1

2

3

4

let VAR_NAME=ARITHMATIC_EXPRESSION

VAR_NAME=$[ARITHMATIC_EXRESSION]

VAR_NAME=$((EXPRESSION))

VAR_NAME=$(expr $num1 + $num2)

算术运算符:

1

2

3

4

5

6

+:加法

-:减法

*:乘法

/:整除

%:取余数

**:乘幂

注意:即使没有定义为整型变量,字符型的数字依然可以参与算术运算,bash会执行变量类型的隐式类型转换。

逻辑运算

1

2

3

4

5

6

7

8

9

10

11

布尔运算:真,假

与运算:真 && 真 = 真

       真 && 假 = 假

       假 && 真 = 假

       假 && 假 = 假

或运算:真 || 真 = 真

   真 || 假 = 真

   假 || 真 = 真

   假 || 假 = 假

非运算:!真=假

       !假=真

bash编程之条件测试语句

bash条件测试

整型测试:整数比较

例如 [ $num1 -gt $num2 ]

1

2

3

4

5

6

-gt: 大于则为真

-lt: 小于则为真

-ge: 大于等于则为真

-le: 小于等于则为真

-eq: 等于则为真

-ne: 不等于则为真

字符测试:字符串比较

双目:

例如[[ "$str1" > "$str2" ]]

1

2

3

4

5

6

>: 大于则为真

<: 小于则为真

>=:大于等于则为真

<=:小于等于则为真

==:等于则为真

!=:不等于则为真

单目:

1

2

-n String: 是否不空,不空则为真,空则为假

-z String: 是否为空,空则为真,不空则假

文件测试:判断文件的存在性及属性等

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

-a FILE:存在则为真;否则则为假;

-e FILE: 存在则为真;否则则为假;

-f FILE: 存在并且为普通文件,则为真;否则为假;

-d FILE: 存在并且为目录文件,则为真;否则为假;

-L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;

-b: 存在并且为块设备,则为真;否则为假;

-c: 存在并且为字符设备,则为真;否则为假

-S: 存在并且为套接字文件,则为真;否则为假

-p: 存在并且为命名管道,则为真;否则为假

-s FILE: 存在并且为非空文件则为值,否则为假;

-r FILE:文件可读为真,否则为假

-w FILE:文件可写为真,否则为假

-x FILE:文件可执行为真,否则为假

file1 -nt file2: file1的mtime新于file2则为真,否则为假;

file1 -ot file2:file1的mtime旧于file2则为真,否则为假;

组合条件测试:在多个条件间实现逻辑运算

1

2

3

4

5

6

7

8

9

10

11

与:[ condition1 -a condition2 ]

   condition1 && condition2

或:[ condition1 -o condition2 ]

   condition1 || condition2

非:[ -not condition ]

   ! condition

与:COMMAND1 && COMMAND2

COMMAND1如果为假,则COMMAND2不执行

或:COMMAND1 || COMMAND2

COMMAND1如果为真,则COMMAND2不执行

非:! COMMAND

条件测试之if语句

if语句之单分支

语句结构:

1

2

3

if 测试条件;then

  选择分支

fi

表示条件测试状态返回值为值,则执行选择分支

例:写一个脚本,接受一个参数,这个参数是用户名;如果此用户不存在,则创建该用户;

1

2

3

4

#!/bin/bash

if id $1 &> /dev/null;then

   useradd $1

fi

if语句之双分支

语句结构:

1

2

3

4

5

if 测试条件;then

  选择分支1

else

  选择分支2

fi

两个分支仅执行其中之一

例:通过命令行给定一个文件路径,而后判断:如果此文件中存在空白行,则显示其空白行的总数;否则,则显示无空白行;

1

2

3

4

5

6

#!/bin/bash

if grep "^[[:space]]*$" $1 &> /dev/nullthen

   echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."

else

   echo "No blank lines"

fi

注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。

补充:bash交互式编程

read [option] “prompt”

1

2

3

-p:直接指定一个变量接受参数

-t timaout:指定等待接受参数的时间

-n:表示不换行

例:输入用户名,可返回其shell

1

2

3

4

5

6

7

#!/bin/bash

read -p "Plz input a username: " userName

if id $userName &> /dev/nullthen

   echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."

else

   echo "No such user. stupid."

fi

if语句之多分支

语句结构:

1

2

3

4

5

6

7

8

9

10

if 条件1;then

    分支1

elif 条件2;then

    分支2

elif 条件3;then

    分支3

     ...

else

    分支n

fi

例:传递一个用户名给脚本:如果此用户的id号为0,则显示说这是管理员;如果此用户的id号大于等于500,则显示说这是普通用户;否则,则说这是系统用户。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#!/bin/bash

if [ $# -lt 1 ]; then

   echo "Usage: `basename $0` username"

   exit 1

fi

if id -u $1 &> /dev/nullthen

   echo "Usage: `basename $0` username"

   echo "No this user $1."

   exit 2

fi

if [ $(id -u $1) -eq 0 ]; then

   echo "Admin"

elif [ $(id -u $1) -ge 500 ]; then

   echo "Common user."

else

   echo "System user."

fi

条件测试之case语句

case语句:有多个测试条件时,case语句会使得语法结构更明晰

语句结构:

1

2

3

4

5

6

7

8

9

10

11

12

case 变量引用 in

PATTERN1)

   分支1

;;

PATTERN2)

   分支2

;;

...

*)

   分支n

;;

esac

PATTERN:类同于文件名通配机制,但支持使用|表示或者

1

2

3

4

a|b: a或者b

*:匹配任意长度的任意字符

?: 匹配任意单个字符

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

例:写一个脚本,完成如下任务,其使用形式如下所示:

script.sh {start|stop|restart|status}

其中:

如果参数为空,则显示帮助信息,并退出脚本;

如果参数为start,则创建空文件/var/lock/subsys/script,并显示“starting script successfully.”

如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop script successfully.”

如果参数为restart,则删除文件/var/locksubsys/script并重新创建,而后显示“Restarting script successfully.”

如果参数为status,那么:如果文件/var/lock/subsys/script存在,则显示“Script is running…”,否则,则显示“Script is stopped.”

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

#!/bin/bash

file='/var/lock/subsys/script'

case $1 in

start)

 if [ -f $file ];then

   echo "Script is running..."

     exit 3

 else

   touch $file

   [ $? -eq 0 ] && echo "Starting script successfully."

 fi

 ;;

stop)

 if [ -f $file ];then

   rm -rf $file

   [ $? -eq 0 ] && echo "Stop script successfully."

 else

   echo "Script is stopped..."

   exit 4

 fi

 ;;

restart)

 if [ -f $file ];then

   rm -rf $file

   [ $? -eq 0 ] && echo "Stop script successfully"

 else

   echo "Script is stopped..."

   exit 5

 fi

   touch $file

   [ $? -eq 0 ] && echo "Starting script successfully"

 ;;

status)

 if [ -f $file ];then

   echo "Script is running..."

 else

   echo "Script is stopped."

 fi

 ;;

*)

   echo "`basename $0` {start|stop|restart|status}"

   exit 2

 ;;

 esac

bash编程之循环语句

循环之for循环

for语句格式一

语句结构:

1

2

3

for 变量名 in 列表; do

   循环体

done

列表:可包含一个或多个元素

循环体:依赖于调用变量来实现其变化

循环可嵌套

退出条件:遍历元素列表结束

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

1

2

3

4

5

6

#!/bin/bash

declare -i sum=0

for in {1..100}; do

   let sum+=$i

done

echo $sum

for语句格式二

1

2

3

for ((初始条件;测试条件;修改表达式)); do

     循环体

done

先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式,否则直接跳出循环。

例:求100以内所有正整数之和(for二实现)

1

2

3

4

5

6

#!/bin/bash

declare -i sum=0

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

   let sum+=$counter

done

echo $sum

循环之while语句

while适用于循环次数未知,或不便用for直接生成较大的列表时

语句结构:

1

2

3

while 测试条件; do

   循环体

done

测试条件为真,进入循环;测试条件为假,退出循环

例:求100以内所有偶数之和,要求使用取模方法

1

2

3

4

5

6

7

8

9

10

#!/bin/bash

declare -i counter=1

declare -i sum=0

while [ $counter -le 100 ]; do

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

        let sum+=$counter

   fi

   let counter++

done

echo $sum

例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止

1

2

3

4

5

6

7

8

9

10

#!/bin/bash

read -p "Plz enter a username: " userName

while "$userName" != 'q' -a "$userName" != 'quit' ]; do

   if id $userName &> /dev/nullthen

      grep "^$userName\>" /etc/passwd cut -d: -f3,7

   else

       echo "No such user."

   fi

read -p "Plz enter a username again: " userName

done

while特殊用法:遍历文本文件

语句结构:

1

2

3

while read 变量名; do

   循环体

done /path/to/somefile

变量名,每循环一次,记忆了文件中一行文本

例:显示ID号为偶数,且ID号同GID的用户的用户名、ID和SHELL

1

2

3

4

5

6

7

while read line; do

   userID=`echo $line | cut -d: -f3`

   groupID=`echo $line | cut -d: -f4`

   if [ $[$userID%2] -eq 0 -a $userID -eq $groupID ]; then

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

   fi

done /etc/passwd

循环之until语句

语句结构:

1

2

3

until 测试条件; do

     循环体

done

测试条件为假,进入循环;测试条件为真,退出循环

例:求100以内所有偶数之和,要求使用取模方法(until实现)

1

2

3

4

5

6

7

8

9

10

#!/bin/bash

declare -i counter=1

declare -i sum=0

until [ $counter -gt 100 ]; do

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

        let sum+=$counter

   fi

   let counter++

done

echo $sum

例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止(until实现)

1

2

3

4

5

6

7

8

9

10

#!/bin/bash

read -p "Plz enter a username: " userName

until "$userName" 'q' -a "$userName" 'quit' ]; do

   if id $userName &> /dev/nullthen

      grep "^$userName\>" /etc/passwd cut -d: -f3,7

   else

       echo "No such user."

   fi

read -p "Plz enter a username again: " userName

done

循环之循环控制和shift

循环控制命令:

break:提前退出循环

break [N]: 退出N层循环;N省略时表示退出break语句所在的循环

continue: 提前结束本轮循环,而直接进入下轮循环

continue [N]:提前第N层的循环的本轮循环,而直接进入下轮循环

死循环:

1

2

3

4

5

6

7

8

#while体

while truedo

     循环体

done

#until体

until falsedo

     循环体

done

例:写一个脚本,判断给定的用户是否登录了当前系统

(1) 如果登录了,则脚本终止;

(2) 每5秒种,查看一次用户是否登录;

1

2

3

4

5

6

7

8

9

#!/bin/bash

while truedo

   who grep "gentoo" &> /dev/null

   if [ $? -eq 0 ];then

break

   fi

   sleep 5

done

echo "gentoo is logged."

shift:如果没有数字,只有shift 就是跳过一个参数获取下一个参数,如果加上数字,比如shift 2 ,跳过两个参数获取下一个参数。

例:写一个脚本,使用形式如下所示

showifinfo.sh [-i INTERFACE|-a] [-v]

要求:

1、-i或-a不可同时使用,-i用于指定特定网卡接口,-a用于指定所有接口;

显示接口的ip地址

2、使用-v,则表示显示详细信息

显示接口的ip地址、子网掩码、广播地址;

3、默认表示仅使用-a选项;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

#!/bin/bash

allinterface=0

ifflag=0

verbose=0

interface=0

if [ $# -eq 0 ];then

   ifconfig grep "inet addr:" awk '{print $2}'

fi

while [ $# -ge 1 ];do

 case $1 in

 -a)

   allinterface=1

   shift 1

 ;;

 -i)

   ifflag=1

   interface=$2

   shift 2

 ;;

 -v)

   verbose=1

   shift 1

 ;;

 *)

   echo "error option"

   exit 2

 ;;

 esac

done

if [ $allinterface -eq 1 ];then

 if [ $ifflag -eq 1 ];then

     echo "command not found"

     exit 5

 fi

 if [ $verbose -eq 1 ];then

     ifconfig grep "inet addr:"

 else

     ifconfig grep "inet addr:" awk '{print $2}'

 fi

fi

if [ $ifflag -eq 1 ];then

 if [ $allinterface -eq 1 ];then

       echo "command not found"

       exit 5

 fi

 if [ $verbose -eq 1 ];then

     ifconfig $interface | grep "inet addr:"

 else

     ifconfig $interface | grep "inet addr:" awk '{print $2}'

 fi

fi

bash编程之函数

语法结构:

1

2

3

4

5

6

7

function F_NAME {

       函数体

   }

   F_NAME() {

       函数体

   }

可调用:使用函数名,函数名出现的地方,会被自动替换为函数

函数的返回值:

函数的执行结果返回值:代码的输出

函数中使用打印语句:echo, printf

函数中调用的系统命令执行后返回的结果

执行状态返回值:

默认取决于函数体执行的最后一个命令状态结果

自定义退出状态码:return [0-255]

注意:函数体运行时,一旦遇到return语句,函数即返回;

函数可以接受参数:

在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:位置参数

$1, $2, …

$#, $*, $@

例:写一个脚本,完成如下功能(使用函数):

1、提示用户输入一个可执行命令;

2、获取这个命令所依赖的所有库文件(使用ldd命令);

3、复制命令至/mnt/sysroot/对应的目录中

解释:假设,如果复制的是cat命令,其可执行程序的路径是/bin/cat,那么就要将/bin/cat复到/mnt/sysroot/bin/目录中,如果复制的是useradd命令,而useradd的可执行文件路径为/usr/sbin/useradd,那么就要将其复制到/mnt/sysroot/usr/sbin/目录中;

4、复制各库文件至/mnt/sysroot/对应的目录中;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#!/bin/bash

#

target=/mnt/sysroot/

[ -d $target ] || mkdir $target

preCommand() {

   if which $1 &> /dev/nullthen

   commandPath=`which --skip-alias $1`

   return 0

   else

   echo "No such command."

   return 1

   fi

}

commandCopy() {

   commandDir=`dirname $1`

   [ -d ${target}${commandDir} ] || mkdir -p ${target}${commandDir}

   [ -f ${target}${commandPath} ] || cp $1 ${target}${commandDir}

}

libCopy() {

   for lib in `ldd $1 | egrep -o "/[^[:space:]]+"`; do

   libDir=`dirname $lib`

   [ -d ${target}${libDir} ] || mkdir -p ${target}${libDir}

   [ -f ${target}${lib} ] || cp $lib ${target}${libDir}

   done

}

read -p "Plz enter a command: " command

until "$command" == 'quit' ]; do

 if preCommand $command &> /dev/nullthen

   commandCopy $commandPath

   libCopy $commandPath

 fi

 read -p "Plz enter a command: " command

done

bash编程之信号捕捉

trap命令用于在shell程序中捕捉到信号,之后可以有三种反应方式:

(1)执行一段程序来处理这一信号

(2)接受信号的默认操作

(3)忽视这一信号

trap对上面三种方式提供了三种基本形式:

第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双引号中的命令串。

trap 'commands' signal-list

trap "commands" signal-list

第二种形式的trap命令恢复信号的默认操作:trap signal-list

第三种形式的trap命令允许忽视信号:trap " " signal-list

trap 'COMMAND' SIGINT(表示关闭进程)

例:写一个脚本,能够ping探测指定网络内的所有主机是否在线,当没有执行完时可接收ctrl+c命令退出。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#!/bin/bash

quitScript() {

    echo "Quit..."

}    

trap 'quitScript; exit 5' SIGINT

cnetPing() {

   for in {1..254}; do

       if ping -c 1 -W 1 $1.$i &> /dev/nullthen

           echo "$1.$i is up."

        else

           echo "$1.$i is down."

       fi

       done

}

bnetPing() {

   for in {0..255}; do

       cnetPing $1.$j

   done

}

anetPing() {

   for in {0..255}; do

       bnetPing $1.$m

   done

}

netType=`echo $1 | cut -d"." -f1`

if [ $netType -ge 1 -a $netType -le 126 ]; then

   anetPing $netType

elif [ $netType -ge 128 -a $netType -le 191 ]; then

   bnetPing $(echo $1 | cut -d'.' -f1,2)

elif [ $netType -ge 192 -a $netType -le 223 ]; then

   cnetPing $(echo $1 | cut -d'.' -f1-3)

else

   echo "Wrong"

   exit 2

fi

bash编程之数组

数组:连续的多个独立内存空间,每个内存空间相当于一个变量

数组元素:数组名+索引(从0开始编号)

索引的表示方式:a[0], a[1]

声明数组:declare -a ARRAR_NAME

关联数组:declare -A ARRAY_NAME

支持稀疏格式:仅一维数组

数组元素的赋值:

(1) 一次只赋值一个元素

a[0]=$RANDOM

(2) 一次赋值全部元素

a=(red blue yellow green)

(3) 指定索引进行赋值

a=([0]=green [3]=red [2]=blue [6]=yellow)

(4) 用户输入

read -a ARRAY

数组的访问:

用索引访问:ARRAY[index]

数组的长度:

${#ARRAY[*]}

${#ARRAY[@]}

例:写一个脚本,生成10个随机数,保存至数组中;而后显示数组下标为偶数的元素

1

2

3

4

5

#!/bin/bash

for in {0..9}; do

   rand[$i]=$RANDOM

   [ $[$i%2] -eq 0 ] && echo "$i:${rand[$i]}"

done

从数组中挑选某元素:

${ARRAY[@]:offset:number}

切片:

offset: 偏移的元素个数

number: 取出的元素的个数

${ARRAY[@]:offset}:取出偏移量后的所有元素

${ARRAY[@]}: 取出所有元素

数组复制:

要使用${ARRAY[@]}

$@: 每个参数是一个独立的串

$*: 所有参数是一个串

向数组中追加元素:非稀疏格式

week,

week[${#week[@]}]

从数组中删除元素:

unset ARRAY[index]

例:复制一个数组中下标为偶数的元素至一个新数组中

1

2

3

4

5

6

7

8

9

10

11

#!/bin/bash

declare -a mylogs

logs=(/var/log/*.log)

echo ${logs[@]}

for in `seq 0 ${#logs[@]}`; do

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

       index=${#mylogs[@]}

        mylogs[$index]=${logs[$i]}

   fi

done

echo ${mylogs[@]}

例:生成10个随机数,升序排序

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#!/bin/bash

for((i=0;i<10;i++))

do

   rnd[$i]=$RANDOM

done

echo -e "total=${#rnd[@]}\n${rnd[@]}\nBegin to sort"

for((i=9;i>=1;i--))

do

       for((j=0;j<i;j++))

   do

   if [ ${rnd[$j]} -gt ${rnd[$[$j+1]]} ] ;then

       swapValue=${rnd[$j]}

       rnd[$j]=${rnd[$[$j+1]]}

       rnd[$[$j+1]]=$swapValue    

   fi

   done

done

echo ${rnd[@]}

例:打印九九乘法表

1

2

3

4

5

6

7

8

9

10

#!/bin/bash

for((i=1;i<=9;i++))

do

strLine=""

   for((j=1;i<=9;j++))

   do

       strLine=$strLine"$i*$j="$[$i*$j]"\t"

       [ $i -eq $j ] && echo -e $strLine && break

   done

done

bash编程之字符串操作

字符串切片:

${string:offset:length}

1

2

3

[root@scholar scripts]# string='hello word'

[root@scholar scripts]# echo ${string:2:4}

llo

取尾部的指定个数的字符:

${string: -length}

1

2

[root@scholar scripts]# echo ${string: -2}

rd

取子串:基于模式

${variable#*word}:在variable中存储字串上,自左而右,查找第一次出现word,删除字符开始至此word处的所有内容;

${variable##*word}:在variable中存储字串上,自左而右,查找最后一次出现word,删除字符开始至此word处的所有内容;

1

2

3

file='/var/log/messages'

${file#*/}: 返回的结果是var/log/messages

${file##*/}: 返回messages

${variable%word*}: 在variable中存储字串上,自右而左,查找第一次出现word,删除此word处至字串尾部的所有内容;

${variable%%world*}:在variable中存储字串上,自右而左,查找最后一次出现word,删除此word处至字串尾部的所有内容;

1

2

3

file='/var/log/messages'

${file%*/}: 返回的结果是/var/log

${file%%*/}: 返回结果为空

例:url="http://www.redhat.com:80"

1

2

取端口:${url##*:}

取协议:${url%%:*}

查找替换:

${variable/pattern/substi}: 替换第一次出现

1

2

3

4

5

#userinfo=`tail -1 /etc/passwd

#echo $userinfo

scholar:x:500:500:scholar:/home/scholar:/bin/bash

#echo ${userinfo/scholar/redhat}

redhat:x:500:500:scholar:/home/scholar:/bin/bash

${variable//pattern/substi}:替换所有的出现

1

2

#echo ${userinfo//scholar/redhat}

redhat:x:500:500:redhat:/home/redhat:/bin/bash

${variable/#pattern/substi}:替换行首被pattern匹配到的内容

1

2

#echo ${userinfo/#scholar/redhat}

redhat:x:500:500:scholar:/home/scholar:/bin/bash

${variable/%pattern/substi}:替换行尾被pattern匹配到的内容

1

2

#echo ${userinfo/%bash/redhat}

scholar:x:500:500:scholar:/home/scholar:/bin/redhat

pattern可以使用globbing中的元字符:* ?

查找删除:

${variable/pattern}:删除第一次出现

1

2

#echo ${userinfo/scholar}

:x:500:500:scholar:/home/scholar:/bin/bash

${variable//pattern}:删除所有的出现

1

2

#echo ${userinfo//scholar}

:x:500:500::/home/:/bin/bash

${variable/#pattern}:删除行首被pattern匹配到的内容

1

2

#echo ${userinfo/#scholar}

:x:500:500:scholar:/home/scholar:/bin/bash

${variable/%pattern}:删除行尾被pattern匹配到的内容

1

2

#echo ${userinfo/%bash}

scholar:x:500:500:scholar:/home/scholar:/bin/

大小写转换:

小–>大:${variable^^}

1

2

#echo ${userinfo^^}

SCHOLAR:X:500:500:SCHOLAR:/HOME/SCHOLAR:/BIN/BASH

大–>小:${variable,,}

1

2

3

#name="SCHOLAR"

#echo ${name,,}

scholar

变量赋值操作:

${variable:-string}:variable为空或未设定,那么返回string,否则,返回variable变量的值;

${variable:=string}:variable为空或未设定,则返回string,且将string赋值给变量variable,否则,返回variable的值;

为脚本使用配置文件,并确保某变量有可用值的方式

variable=${variable:-default vaule}

写个脚本,配置etc目录;

(1) 在配置文件中定义变量;

(2) 在脚本中source配置文件;

1

2

3

4

5

#!/bin/bash

[ -f /etc/sysconfig/network ] && source /etc/network/network

[-z "$HOSTAME" -o "$HOSTNAME" '(none)' ] || HOSTNAME ='localhost'

/bin/hostname $HOSTNAME

/bin/hostname

bash编程之补充

mktemp命令:

mktemp [OPTIONS] filename.XXX

1

2

-d: 创建临时目录

--tmpdir=/path/to/somewhere :指定临时文件所在的目录

1

2

3

mktemp /tmp/tmp.XXX                    #XXX生成相同数量随机字符

mktemp --tmpdir=/var/tmp tmp.XXX       #指定目录创建临时文件

mktemp --tmpdir=/var/tmp -d tmp.XXX    #指定目录创建临时目录

install命令:

install [OPTIONS] SOURCE DEST

install [OPTIONS] SOURCE… DIR

install [OPTIONS] -d DIR …

增强型的复制命令:

1

2

3

-o OWNER

-g GROUP

-m MODE

1

-d : 创建目录

1

2

3

4

5

install /etc/fstab /tmp                 #复制文件到指定目录

install --mode=644 /etc/fstab /tmp/     #复制时指定权限

install --owner=scholar /etc/fstab /tmp #复制时指定属主

install --group=scholar /etc/fstab /tmp #复制时指定属组

install -d /tmp/install                 #创建目录

The end

至此,bash编程的所有基础语法知识点就总结完毕了,掌握了以上知识点,bash编程算是略有小成了吧,如果有兴趣可继续钻研高级语法,目前能力不足就不介绍啦。这里给大家推荐两本bash编程的书籍,能力相对较弱的可以看一下《Linux命令行和shell编程宝典》,有能力的就看《abs-guide》吧。看在码字辛苦的份上,多多点赞吧。


你可能感兴趣的:(bash基础)