加载中...
Linux Shell进阶
发表于:2021-09-14 | 分类: 平台

# 4 并发控制

  • 默认情况下,Shell 命令是串行方式自上而下执行的,但如果有大量的命令需要执行,串行就会浪费大量的时间,这就需要采用并发执行。

# 4.1 利用后台执行实现并发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@hdp-1 shell]# cat back_ping.sh 
#!/bin/bash
for i in {1..254}
do
{
ip=10.10.10.$i
ping -c1 -w1 $ip &> /dev/null
if [ $? -eq 0 ];then
echo "$ip is up."
else
echo "$ip is down."
fi
}&
done
wait
echo "Mission Completed"

# 利用管道实现并发控制

  • 使用 Linux 管道文件特性制作队列,可以控制并发数量。
  • 管道分为命名管道和匿名管道。
  • 创建命名管道文件命令是 mkfifo
  • 命名管道可跨终端实现数据交换
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
[root@hdp-1 shell]# cat 255_ping.sh 
thread=5
tmp_fifofile=/tmp/$$.fifo
mkfifo $tmp_fifofile
exec 8<>$tmp_fifofile
rm $tmp_fifofile
for i in `seq $thread`
do
echo >&8
done

for i in {1..254}
do
read -u 8
{
ip=10.0.0.$i
ping -c1 -w1 $ip &>/dev/null
if [ $? -eq 0 ];then
echo "$ip is up."
else
echo "$ip is down . "
fi
echo >&8
}&
done
wait
exec 8>&-
echo "misson completed."

# 5 Shell 数组

# 5.1 Shell 数组的基本概念

  • 用于区分不同元素的编号称为数组下标。
  • 数组的元素有时也称为下标变量。
  • 数组分为普通数组和关联数组
  • 普通数组中的索引是整数,关联数组的数组索引可以用文本。
  • 关联数组使用之前需要声明
  • 关联数组由键值对组成。

# 5.1.1 普通数组

  • 普通数组中:数组元素的索引(下标)从 0 开始编号,获取数组中的元素要利用索引(下标)。索引(下标)可以是算术表达式,其结果必须是一个整数。
  • 普通数组定义。
  • 下标从 0 开始
1
2
3
[root@hdp-1 shell]# books=(linux shell awk openstack docker)
[root@hdp-1 shell]# echo ${books[3]}
openstack

# 5.1.2 关联数组

  • 关联数组和普通数组所不同的是,它的索引下标可以是任意的整数和字符串。
  • 关联数组定义。eg: info=([name]=tianyun [sex]=male [age]=36 [height]=170 [skill]=cloud)

# 5.1.3 数组声明

  • 关联数组需要先声明后使用。
  • 通常情况下 Shell 解释器隐式声明普通数组。
  • 声明普通数组的方法为:
1
declare -a array
  • 声明关联数组的方法为:
1
declare -A array

# 5.2 Shell 数组的定义

  • 在 Linux Shell 中,定义一个数组有多种方法,需要先按照命令规则给数组命名,然后再定义数组的值。数组的定义方法有直接定义数组、下标定义数组、间接定义数组和从文件中读入定义数组,接下来详细介绍定义数组的方法。

# 5.2.1 直接定义数组

  • 直接定义数组是用小括号将变量值括起来赋值给数组变量,每个变量值之间要用空隔进行分隔。
1
2
3
[root@hdp-1 shell]# books=(linux shell awk openstack docker)
[root@hdp-1 shell]# echo ${books[3]}
openstack

# 5.2.2 下标定义数组

  • 下标定义数组是用小括号将变量值括起来,同时采用键值对的形式赋值。
1
array_name=([1]=value1 [2]=value2 [3]=value3 ...)
  • 此种方法为 key-value 键值对的形式,小括号里对应的数字为数组下标,等号后面的内容为下标对应的数组变量的值。
1
2
3
4
5
6
[root@hdp-1 shell]# declare -A info
[root@hdp-1 shell]# info=([name]=tianyun [sex]=male [age]=36 [height]=170 [skill]=cloud)
[root@hdp-1 shell]# echo ${info[name]}
tianyun
[root@hdp-1 shell]# echo ${info[skill]}
cloud

# 5.2.3 间接定义数组

  • 间接定义数组是分别通过定义数组的方法来定义。其语法格式为:
1
array_name[0]=value1;array_name[1]=value2;array_name[2]=value3 
  • 此种方法要求一次赋一个值,比较复杂。具体如下所示。
  • 间接定义数组。
1
2
3
4
5
6
7
[root@hdp-1 shell]# array[0]=pear
[root@hdp-1 shell]# array[1]=apple
[root@hdp-1 shell]# array[2]=orange
[root@hdp-1 shell]# echo ${array[1]}
apple
[root@hdp-1 shell]# echo "You are the ${array[1]} of my eye."
You are the apple of my eye.

# 5.2.4 从文件中读入定义数组

  • 从文件中读入定义数组是使用命令的输出结果作为数组的内容。其语法格式为:
1
2
3
4
5
array_name=(${命令})
数组名=($(`变量名`))
或者
array_name=(`命令`)
数组名=(`变量值`)
  • 这种方法要求一次赋多个值。
  • 从文件中读入定义数组。
1
2
3
[root@hdp-1 shell]# array=(`cat /etc/passwd`)
[root@hdp-1 shell]# echo ${array[*]}
root:x:0:0:root:/root:/bin/bash

# 5.3 Shell 数组的遍历及赋值

# 5.3.1 常见的访问 Shell 数组表达式

  • 表列出了常见访问数组的表达式。
语法 描述
echo $ 访问数组所有索引
echo $ 访问数组所有索引
echo $ 访问数组所有值
echo $ 访问数组所有值
echo $ 统计数组元素个数
echo $ 访问数组中的第一个元素
echo $ 从数组下标 1 开始
echo $ 从数组下标 1 开始,访问两个元素
echo $ 第 #个元素的字符个数
echo $ 第 0 个元素的字符个数
echo $ 显示第 #个元素
echo $ 显示第 0 个与元素

# 5.3.2 while 循环实现 Shell 数组的遍历

  • 以 host 文件的每一行作为数组的一个元素来赋值,并对该数组进行遍历。具体如下所示。
  • while 循环实现 Shell 数组的遍历。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat array_host_while.sh 
#!/bin/bash
while read line
do
hosts[++i]=$line

done </etc/hosts

echo "hosts first : ${hosts[1]}"
echo

for i in ${!hosts[@]}
do
echo "$i: ${hosts[i]}"
done

  • while 读入 /etc/hosts 文件的每一行并把它显示出来,hosts [++i]=line这个表达式完成数组的赋值操作,line这个表达式完成数组的赋值操作,{!hosts [@]} 这个表达式获得数组的索引,${hosts [i]} 这个表达式完成了数组的遍历。
  • 执行结果如下:
1
2
3
4
5
6
7
8
9
10
[root@hdp-1 shell]# ./array_host_while.sh 
hosts first : 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4

1: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2: ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
3:
4: 172.18.*.* as
5: 172.18.*.* hdp-1
6: 172.18.*.* hdp-2
7: 172.18.*.* hdp-3

# 5.3.3 for 循环实现 Shell 数组的遍历

  • 当一个脚本需要传入的参数较多时,可以使用 for 循环进行参数遍历。具体如下例所示。
  • for 循环实现 Shell 数组的遍历。
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@hdp-1 shell]# cat array_host_for.sh 
#!/bin/bash
#for array
OLD_IFS=$IFS
IFS=$'\n'
for line in `cat /etc/hosts`
do
hosts[++j]=$line
done
for i in ${!hosts[@]}
do
echo "$i: ${hosts[i]}"
done
  • 定义一个数组 hosts 以 /etc/hosts 每一行内容作为数组的元素进行遍历。
  • 执行结果如下:
1
2
3
4
5
6
7
8
[root@hdp-1 shell]# ./array_host_for.sh 
1: 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2: ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
3:
4: 172.18.*.* as
5: 172.18.*.* hdp-1
6: 172.18.*.* hdp-2
7: 172.18.*.* hdp-3

# 6 Shell 函数

# 6.1 Shell 函数的概念

  • 函数是由若干条 Shell 命令组成的语句块,实现代码重用和模块化编程,它不是一个单独的进程,不能独立运行,它只是 Shell 程序的一部分。
  • Shell 函数和 Shell 程序比较相似,区别在于:Shell 程序在子 Shell 中运行,而 Shell 函数在当前 Shell 中运行,因此在当前 Shell 中,函数可以对 Shell 变量进行修改。
  • 函数可以提高程序的可读性和重用性。

# 6.2 Shell 函数的语法

  • Shell 函数的语法格式为:
1
2
3
4
5
6
7
函数名(){
代码块
}
or
function 函数名 {
代码块
}
  • 关键字 function 表示定义一个函数,可以省略,其后是函数名,两个大括号之间是函数体。创建的函数可以在别的脚本中被调用。

# 6.3 Shell 函数的调用

# 6.3.1 Shell 函数的传参介绍

  • 最基本的语法格式为:
1
函数名
  • 带有参数的语法格式为:
1
函数名 参数1 参数2
  • Shell 的位置参数($1、$2、…)可以作为函数的参数来使用。其中,$1 表示第一个参数,$2 表示第二个参数。
  • 当 n≥10 时,需要使用 ${n} 来获取参数。例如,获取第十个参数不能用10,需要用10,需要用 {10}。

# 6.4 Shell 函数的应用实战

# 6.4.1 脚本中调用 Shell 函数

  • 函数必须在使用前需要先被定义。因此,在脚本中使用函数时,必须在脚本开始前定义函数,调用函数仅使用函数名即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@hdp-1 shell]# ./function.sh 
5的阶乘是: 120
[root@hdp-1 shell]# cat function.sh
#!/bin/bash
factorial(){
factorial=1
for((i=1;i<=5;i++))
do
factorial=$[$factorial * $i]
done
echo "5的阶乘是: $factorial"
}

factorial
  • 接下来使用带有可以传参调用的函数来写一个计算阶乘的脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@hdp-1 shell]# ./function.sh 5
5的阶乘是: 120
[root@hdp-1 shell]# cat function.sh
#!/bin/bash
factorial(){
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial * $i]
done
echo "5的阶乘是: $factorial"
}

factorial $1
  • 函数的位置参数与脚本的位置参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@hdp-1 shell]# ./position_func.sh 2 3 4
result is : 24
[root@hdp-1 shell]# cat position_func.sh
#!/bin/bash
if [ $# -ne 3 ];then
echo "usage: `basename $0` p1 p2 p3"
exit
fi
fun(){
echo "$[$1*$2*$3]"
}

#result
result=`fun $1 $2 $3`
echo "result is : $result"

# 6.4.2 Shell 函数的返回值

  • 函数有两种返回值,分别为执行结果的返回值和退出状态码。
  • 函数的退出状态码取决于函数中执行的最后一条命令的退出状态码。
  • 自定义退出状态码的语法格式为:
1
2
return 0 无错误返回
return 1-255 有错误返回
  • 退出状态码使用 return 保留字返回
  • return 的返回值只能是 0~255 的一个整数
  • 执行结果的返回值不使用 return
  • 执行结果的返回值将保存到变量 “$?” 中
  • 函数执行结果的的返回值。
1
2
3
4
5
6
7
8
9
10
11
12
[root@hdp-1 shell]# ./return.sh 
Enter a Number: 3
fun2 return value: 0
[root@hdp-1 shell]# cat return.sh
#!/bin/bash
fun2(){
read -p "Enter a Number: " num
let 2*num
}

fun2
echo "fun2 return value: $?"

# 6.4.3 Shell 函数数组变量的传参

  • 向函数中传递数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@hdp-1 shell]# ./array_func.sh 
120
[root@hdp-1 shell]# cat array_func.sh
#!/bin/bash
num=(1 2 3 4 5)

array(){
result=1
for i in "$@"
do
result=$[$result*$i]
done
echo "$result"
}

array ${num[@]}
上一篇:
Linux Shell条件测试
下一篇:
(1)Hi3861开发板介绍
本文目录
本文目录