Bash 函数
函数可以有效减少您重复编写程序段的工作量,可随时重复调用。
函数声明
首选常用格式,以函数名称开头。
function_name() {
commands
}
以 Function 开头,后接函数名。
function function_name() {
commands
}
两种格式的单行压缩,请仔细对照。
function_name() {commands;}
function function_name() {commands;}
注:
- 请仔细观察空格,严格遵守语法格式。
- commands是函数主体,即命令集。
- 使用单行压缩函数时,;必须跟随函数主体中的最后一个命令。
- 您最好始终保持功能性名称的描述性,以方便您在封装完毕之后调用。
示例:
#!/bin/bash
W3Cschool(){
echo "Welcome to W3Cschool"
}
W3Cschool
执行后得到以下结果:
Welcome to W3Cschool
变量作用域
在 Bash 中,在默认情况下所有变量都定义为全局变量,即使在函数内部声明也是如此。
您可以使用local关键字在函数内部声明局部变量,该变量只能够在该函数内部使用。同其他编程语言一样,这意味着您可以声明相同名称的全局变量。
#!/bin/bash
str1="abc"
str2="bcd"
fun(){
local str1="123"
str2="234"
echo "Inside function:str1_value is ${str1},str2_value is ${str2}."
}
echo "Before executing function:str1_value is ${str1},str2_value is ${str2}."
fun
echo "After executing function:str1_value is ${str1},str2_value is ${str2}."
执行后得到以下结果:
Before executing function:str1_value is abc,str2_value is bcd.
Inside function:str1_value is 123,str2_value is 234.
After executing function:str1_value is abc,str2_value is 234.
注:
- 由执行结果得出。
在变量名相同的情况下,局部变量的优先级在函数内部高于全局变量。可以理解为就近原则。
全局变量可以在函数内部更改它的值。
返回值
在 Bash 函数中,其返回值是执行的最后一个语句的状态。1-255(十进制)范围内表示失败,除此之外表示成功。
您可以使用return语句指定返回状态,并将其分配给$?。该语句会终止函数的调用。如下所示:
#!/bin/bash
fun(){
echo "result"
return 66
}
fun
echo $?
执行后得到以下结果:
result
66
若您想要从函数中返回任意实际的值,最简单的选择是将函数的执行结果分配给一个全局变量,如下所示:
#!/bin/bash
fun(){
fun_result="value"
}
fun
echo $fun_result
执行后得到以下结果:
value
还有一个更好的选择是将值发送到 stdout 再打印输出,如下所示:
#!/bin/bash
fun(){
local fun_result="value"
echo "$fun_result"
}
fun
echo $fun_result
执行后得到以下结果:
value
注:
利用 $()机制将函数执行结果分配给变量fun_result,以此保存函数的执行结果。
参数传递
若您想要将任意数量的参数传递给 Bash 函数,只需要将它们放在调用的函数名后面,以空格分隔,以" "将参数转义。
注:
参数传递的顺序位为 $1、$2···$n,在传参时应严谨的根据需要排序以达到您所期望的效果。
$#保存传递给函数的函数的位置参数或数量。
$*或 $@保存传递给参数的所有位置参数或参数。
示例:
#!/bin/bash
fun(){
echo "Welcome to $1"
}
fun "W3Cschool"
执行后得到以下结果:
Welcome to W3Cschool
Bash 数组
数组声明
索引数组
使用declare加-a选项,将变量来声明数组,语法如下:
#声明数组
declare -a Array_Name
#创建数组元素
Array_Name[index_1]=value_1
Array_Name[index_2]=value_2
#或
Array_Name=(
[index_1]=value_1
[index_2]=value_2
)
注:
- 在 Bash 中命名数组的规则与变量的命名规则相同。
- Array_Name是数组名称。
- index是为正整数的索引。
关联数组
使用declare加-A选项来声明数组,语法如下:
#声明数组
declare -A Array_Name
#创建数组元素
Array_Name[index_1]=value_1
Array_Name[index_2]=value_2
#或
Array_Name=(
[index_1]=value_1
[index_2]=value_2
)
数组初始化
Array_Name=(element_1 element_2 element_3)
注:
- 此处索引从0开始。
- =两侧无空格。
打印数组
declare -p Array_Name
数组运算
访问元素
您要想访问一个元素,首先需要知道该元素的索引下标,然后使用以下语法进行访问获取。
${Array_Name[index]}
如果您使用@或*作为索引进行访问获取,那么将会得到数组中的所有元素。
#!/bin/bash
declare -a arr=("welcome" "to" "W3Cschool")
echo "@"
for i in "${arr[@]}"
do
echo "$i"
done
echo "*"
for i in "${arr[*]}"
do
echo "$i"
done
执行后得到以下结果:
@
welcome
to
W3Cschool
*
welcome to W3Cschool
注:
- @和 *两者的区别主要体现在循环结果的不同。
打印数组键
您还可以检索和打印在数组中使用的键。语法如下:
${!Array_Name[index]}
示例:
#!/bin/bash
declare -a arr=( "Welcome" "To" "W3Cschool" )
echo "${!arr[@]}"
执行后得到以下结果:
0 1 2
查找数组长度
数组长度即数组中的元素个数,语法如下:
${#ARRAY_NAME[@]}
示例:
#!/bin/bash
declare -a arr=( "Welcome" "To" "W3Cschool" )
echo "The array contains ${#arr[@]} elements"
执行后得到以下结果:
The array contains 3 elements
遍历数组
遍历数组的通用方法是 for 循环,如下所示:
#!/bin/bash
declare -a arr=( "Welcome" "To" "W3Cschool" )
for i in "${!arr[@]}"
do
echo The key value of element "${arr[$i]}" is "$i"
done
执行后得到以下结果:
The key value of element Welcome is 0
The key value of element to is 1
The key value of element W3Cschool is 2
添加或删除元素
- 添加元素
Array_Name[index]="New Element"
示例:
#!/bin/bash
declare -a arr=( "Java" "Python" "PHP" "HTML" )
arr[4]="JavaScript"
echo "${arr[@]}"
执行后得到以下结果:
Java Python PHP JavaScript CSS SQL
- 删除元素
unset ARRAY_NAME[index]
示例:
#!/bin/bash
declare -a arr=( "Java" "Python" "HTML" "CSS" "JavaScript" )
unset arr[1]
echo "${arr[@]}"
执行后得到以下结果:
Java HTML CSS JavaScript
删除数组
可以通过将数组名称作为参数传递给unset命令执行删除操作,如下所示:
#!/bin/bash
declare -a arr=( "Java" "Python" "HTML" "CSS" "JavaScript" )
unset arr
echo ${!arr[@]}
echo ${!arr[@]}
执行后返回空结果,数组已不存在。
数组切片
Bash 数组也可以从指定的起始索引切片至指定的结束索引,语法如下:
Slieced_Array=(${Array_Name[@]:m:n}")
示例:
#!/bin/bash
example_array=( "Java" "Python" "HTML" "CSS" "JavaScript" )
sliced_array=("${example_array[@]:1:3}")
for i in "${sliced_array[@]}"
do
echo $i
done
执行后得到以下结果:
Python
HTML
CSS
Bash 读取文件
以下示例均以 ReadFile.txt 文件为例。文件内容如下:
Welcome
To
Our
Website
-
W3Cschool
读取操作
您可以使用cat file_Name来读取文件。
语法:
value=`cat file_Name`
应用示例:
#!/bin/bash
value=`cat ReadFile.txt`
echo "$value"
执
行后得到以下结果:
Welcome
To
Our
Website
-
W3Cschool
您也可以使用$(file_Name)来读取文件。
语法:
value=$(file_Name)
应用示例:
#!/bin/bash
value=$(<ReadFile.txt)
echo "$value"
执行后得到以下结果:
Welcome
To
Our
Website
-
W3Cschool
您还可以使用 while 循环来读取文件。
应用示例:
#!/bin/bash
i=1
while read line; do
#Reading each line
echo "No. $i : $line"
i=$((i+1))
done < ReadFile.txt
执行后得到以下结果:
No. 1 : Welcome
No. 2 : To
No. 3 : Our
No. 4 : Website
No. 5 : -
No. 6 : W3Cschool
注:
- 在这里 i用于给循环迭代出的每一个字符串编号。
- 使用 while 循环来读取文件的写法很灵活多样,但编写简便的代码语句是一个好习惯哦。
Bash 重定向
当一个命令执行时,通常从“标准输入”读取输入,在默认情况下,该“标准输入”为您的终端。以此类比,当一个命令将其输出写入到“标准输出”中,在默认情况下,该“标准输出”同为您的终端。重定向就是将发送目标:终端,更改成指定的文件。
输出重定向
由于>或>>会将输出从终端重定向到指定文件,因此均不会在终端打印输出。>和>>的功能区别,如下所示:
>会以命令中的写入内容覆盖原文件内容。如果指定的文件不存在,那么它将会创建一个以指定文件名命名的新文件,并执行写入操作。
示例:
#!/bin/bash
writefile=WriteFile.txt
$ echo "编程狮:www.w3cschool.cn" > $writefile
#使用 cat 命令打印文件内容
$ cat $writefile
执行后得到以下结果:
编程狮:www.w3cschool.cn
>>会将命令中的写入内容附加到原文件内容末尾。如果指定的文件不存在,那么它将会创建一个以指定文件名命名的新文件,并执行写入操作。
示例:
#!/bin/bash
writefile=WriteFile.txt
$ echo "编程狮:www.w3cschool.cn" > $writefile
$ echo "编程狮:www.w3cschool.cn" >> $writefile
#使用 cat 命令打印文件内容
cat $writefile
执行后得到以下结果:
编程狮:www.w3cschool.cn
编程狮:www.w3cschool.cn
输入重定向
与输出重定向一样,但是符号方向相反。语法展示如下:
command < file
接下来使用 wc命令读取文件行数配合演示示例。 示例:
$ wc -l < WriteFile.txt
注:
- 此处不会输出文件名, < 仅知道从“标准输入”读取的内容。
深入理解
您需要理解以下三个文件概念:
- stdin:标准输入文件,其文件描述符为0,默认由此读取数据。
- stdout:标准输出文件,其文件描述符为1,默认向它输出数据。
- stderr:标准错误文件,其文件描述符为2,默认向它写入错误信息。
#默认情况下
command > file
#将 stdout 重定向到 file
command < file
#将 stdin 重定向到 file
如果想要 stderr重定向到 file ,如下示例:
$ command 'stderr' > file
#或(注意二者的区别)
$ command 'stderr' >> file
注:
- 'stderr’指代标准错误文件,非命令,请不要盲目复制使用。
如果希望对stdin和stdout都进行重定向,将 file1 作为command 的输入,并将 command 的处理结果输出到 flie2 。
command < file1 > file2