Linux基础知识(12)- Shell (五) | 函数、输入/输出重定向、文件包含()

1. 函数

    Linux shell 可以用户定义函数,在 shell 脚本中可以被调用。    1) 函数定义        shell 中函数的定义格式如下:            [ function ] fun [()]            {                action;                [return int;]            }        说明:            (1) 可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数。            (2) 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return 后跟数值 n (0-255)。                示例

 1             #!/bin/bash
 2 
 3             func() {
 4                 echo "第一个函数"
 5             }
 6 
 7             funWithReturn(){
 8                 echo "第二个函数:输入的两个数字进行相加运算 ..."
 9                 echo "输入第1个数字: "
10                 read num1
11                 echo "输入第2个数字: "
12                 read num2
13                 echo "2个数字: $num1, $num2"
14                 return $(($num1+$num2))     # 和 $[$num1+$num2] 同样效果,完成算术运算
15             }
16             
17             echo "---- 函数开始执行 ----"
18 
19             func    # 不带 ()
20             funWithReturn   
21             
22             echo "第二个函数返回值:$?"
23             
24             echo "---- 函数执行结束 ----"

        输出结果:

 1             ---- 函数开始执行 ----
 2             第一个函数
 3             第二个函数:输入的两个数字进行相加运算 ...
 4             输入第1个数字:
 5             3
 6             输入第2个数字:
 7             5
 8             2个数字: 3, 5
 9             第二个函数返回值:8
10             ---- 函数执行结束 ----

        注:            (1) 函数返回值在调用该函数后通过 $? 来获得。            (2) 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。    2) 函数参数        在 Shell 中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1 表示第一个参数,$2 表示第二个参数 …        另外,还有几个特殊字符用来处理参数:

参数 描述
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程 ID 号
$! 后台运行的最后一个进程的 ID 号
$@ 与 $* 相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示 Shell 使用的当前选项,与 set 命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

        示例

 1             #!/bin/bash
 2 
 3             funWithParam(){
 4                 echo "第1个参数: $1"
 5                 echo "第9个参数: $9"
 6                 echo "第10个参数:${10}"
 7                 echo "第11个参数:${11}"
 8                 echo "参数总数\$#:$#"
 9                 echo "所有参数\$*:$*"
10                 echo "所有参数\$@:$@"
11                 echo "当前进程 ID 号\$$:$$"
12             }
13 
14             funWithParam 1 2 3 4 5 6 7 8 9 10 abc

        输出结果:

1             第1个参数: 1
2             第9个参数: 9
3             第10个参数:10
4             第11个参数:abc
5             参数总数$#:11
6             所有参数$*:1 2 3 4 5 6 7 8 9 10 abc
7             所有参数$@:1 2 3 4 5 6 7 8 9 10 abc
8             当前进程 ID 号$$:11025

        注:当 n >= 10 时,需要使用 ${n} 来获取参数。

2. 输入/输出重定向

    在 Unix/Linux 中,接受文本作为输入是通过 stdin (标准输入流)。从命令输出到 Shell 的文本是通过 stdout (标准输出流) 传递。命令的错误消息通过 stderr (标准错误流) 发送。    Unix/Linux 中的流被视为文件,与进程关联的每个文件都分配有一个唯一的编号以进行标识,称为文件描述符。 文件描述符: 0 是标准输入(stdin),1 是标准输出(stdout),2 是标准错误输出(stderr)。    输入/输出在没有重定向的情况下(默认情况),输出到终端,从终端接收输入。    重定向命令列表如下:

命令 描述
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag  将开始标记 tag 和结束标记 tag 之间的内容作为输入。

    1) 标准输出(stdout)重定向        重定向到 file,格式如下:            $ command > file            或            $ command 1> file         以追加方式重定向到 file,格式如下:            $ command >> file            或            $ command 1>> file         示例

            $ echo "重定向到 file,不指定文件描述符" > data.txt
            $ cat data.txt

                重定向到 file,不指定文件描述符

            $ echo "重定向到 file,指定文件描述符" 1> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符   

            $ echo "以追加方式重定向到 file,不指定文件描述符" >> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符
                以追加方式重定向到 file,不指定文件描述符

            $ echo "以追加方式重定向到 file,指定文件描述符" 1>> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符
                以追加方式重定向到 file,不指定文件描述符
                以追加方式重定向到 file,指定文件描述符

            注: “1>” 和 “1>>” 里的文件描述符 “1” 和 “>” 之间不能有空格,如果有空格,“1” 会被作为字符串处理,而不是作为文件描述符来处理。    2) 标准输入(stdin)重定向        格式如下:            $ command < file        示例

1             $ wc -l data.txt    # 统计 data.txt 文件的行数
2                 
3                 3 data.txt      # 文件里有 3 行,并显示文件名
4 
5             $ wc -l < data.txt
6 
7                 3               # 不显示文件名

    3) 标准输出和输入同时重定向            格式如下:            $ command < infile > outfile        示例

1             $ wc -l < data.txt > result.txt     # 统计 data.txt 文件的行数,把统计结果写到 result.txt
2             $ cat result.txt
3 
4                 3 

    4) 标准错误输出(stderr)重定向        重定向到 file,格式如下:            $ command 2> file        以追加方式重定向到 file,格式如下:            $ command 2>> file        将 stderr 和 stdout 合并后重定向到 file,格式如下:            $ command > file 2>&1        将 stderr 和 stdout 合并后重定向到 file,格式如下:            $ command >> file 2>&1        示例

 1             $ ls test.sh aaa.sh     # test.sh 存在,aaa.sh 不存在
 2 
 3                 ls: aaa.sh: No such file or directory
 4                 test.sh
 5 
 6             $ ls test.sh aaa.sh 2> error.txt
 7 
 8                 test.sh
 9 
10             $ cat error.txt
11 
12                 ls: aaa.sh: No such file or directory
13 
14             $ ls bbb.sh 2>> error.txt    # bbb.sh 不存在
15             $ cat error.txt
16 
17                 ls: aaa.sh: No such file or directory
18                 ls: bbb.sh: No such file or directory
19 
20 
21             $ ls test.sh aaa.sh > result.txt 2>&1
22             $ cat result.txt
23 
24                 ls: aaa.sh: No such file or directory
25                 test.sh
26             
27             $ ls test.sh bbb.sh >> result.txt 2>&1
28             $ cat result.txt
29 
30                 ls: aaa.sh: No such file or directory
31                 test.sh
32                 ls: bbb.sh: No such file or directory
33                 test.sh

             注:                              (1) “2>” 和 “2>>” 里的文件描述符 “2” 和 “>” 之间不能有空格,如果有空格,“2” 会被作为字符串处理,而不是作为文件描述符来处理。                (2) “2>&1” 是一个整体,中间不能有空格,“2” 和 “1” 的位置不能交换。    5) Here Document        Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。        格式如下:            command << delimiter                document            delimiter        它的作用是将两个 delimiter 之间的内容 (document) 作为输入传递给 command。        注:结尾的 delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的 delimiter 前后的空格会被忽略掉。        在命令行中通过 wc -l 命令计算 Here Document 的行数:

1             $ wc -l << EOF  # 按回车键,进入输入模式,输入 3 行
2             >Hello world
3             >Good 123
4             >www.test.com
5             >EOF       # 输入 EOF,按回车键,退出输入模式
6 
7             3          # 输出结果为 3 行

        也可以将 Here Document 用在脚本中,例如:

1             #!/bin/bash
2 
3             cat << EOF
4             Hello world
5             Good 123
6             www.test.com
7             EOF

        执行以上脚本,输出结果:            Hello world            Good 123            www.test.com    6) /dev/null 文件        如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:            $ command > /dev/null        /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到 “禁止输出” 的效果。        如果希望屏蔽 stdout 和 stderr,可以这样写:            $ command > /dev/null 2>&1            注:”2>&1″ 是一个整体,中间不能有空格,“2” 和 “1” 的位置不能交换。

3. 文件包含

    Shell 也可以包含外部脚本,可以方便的封装一些公用的代码作为一个独立的文件。    Shell 文件包含的语法格式如下:        . filename   # 注意点号(.)和文件名中间有一空格        或        source filename    创建两个 shell 脚本文件。        demo1.sh 代码如下:            #!/bin/bash            url=”http://www.test.com”        demo2.sh 代码如下:

1             #!/bin/bash
2 
3             # 使用 . 号来引用 demo1.sh 文件
4             . ./demo1.sh
5 
6             # 或者使用以下包含文件代码
7             # source ./demo1.sh
8 
9             echo "Website:$url"

    接下来为 demo2.sh 添加可执行权限并执行:        $ chmod +x demo2.sh         $ ./demo2.sh             Website:http://www.test.com        注:被包含的文件 demo1.sh 不需要可执行权限。

————————

1. 函数

    Linux shell 可以用户定义函数,在 shell 脚本中可以被调用。    1) 函数定义        shell 中函数的定义格式如下:            [ function ] fun [()]            {                action;                [return int;]            }        说明:            (1) 可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数。            (2) 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return 后跟数值 n (0-255)。                示例

 1             #!/bin/bash
 2 
 3             func() {
 4                 echo "第一个函数"
 5             }
 6 
 7             funWithReturn(){
 8                 echo "第二个函数:输入的两个数字进行相加运算 ..."
 9                 echo "输入第1个数字: "
10                 read num1
11                 echo "输入第2个数字: "
12                 read num2
13                 echo "2个数字: $num1, $num2"
14                 return $(($num1+$num2))     # 和 $[$num1+$num2] 同样效果,完成算术运算
15             }
16             
17             echo "---- 函数开始执行 ----"
18 
19             func    # 不带 ()
20             funWithReturn   
21             
22             echo "第二个函数返回值:$?"
23             
24             echo "---- 函数执行结束 ----"

        输出结果:

 1             ---- 函数开始执行 ----
 2             第一个函数
 3             第二个函数:输入的两个数字进行相加运算 ...
 4             输入第1个数字:
 5             3
 6             输入第2个数字:
 7             5
 8             2个数字: 3, 5
 9             第二个函数返回值:8
10             ---- 函数执行结束 ----

        注:            (1) 函数返回值在调用该函数后通过 $? 来获得。            (2) 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。    2) 函数参数        在 Shell 中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1 表示第一个参数,$2 表示第二个参数 …        另外,还有几个特殊字符用来处理参数:

参数 描述
$# 传递到脚本或函数的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程 ID 号
$! 后台运行的最后一个进程的 ID 号
$@ 与 $* 相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示 Shell 使用的当前选项,与 set 命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

        示例

 1             #!/bin/bash
 2 
 3             funWithParam(){
 4                 echo "第1个参数: $1"
 5                 echo "第9个参数: $9"
 6                 echo "第10个参数:${10}"
 7                 echo "第11个参数:${11}"
 8                 echo "参数总数\$#:$#"
 9                 echo "所有参数\$*:$*"
10                 echo "所有参数\$@:$@"
11                 echo "当前进程 ID 号\$$:$$"
12             }
13 
14             funWithParam 1 2 3 4 5 6 7 8 9 10 abc

        输出结果:

1             第1个参数: 1
2             第9个参数: 9
3             第10个参数:10
4             第11个参数:abc
5             参数总数$#:11
6             所有参数$*:1 2 3 4 5 6 7 8 9 10 abc
7             所有参数$@:1 2 3 4 5 6 7 8 9 10 abc
8             当前进程 ID 号$$:11025

        注:当 n >= 10 时,需要使用 ${n} 来获取参数。

2. 输入/输出重定向

    在 Unix/Linux 中,接受文本作为输入是通过 stdin (标准输入流)。从命令输出到 Shell 的文本是通过 stdout (标准输出流) 传递。命令的错误消息通过 stderr (标准错误流) 发送。    Unix/Linux 中的流被视为文件,与进程关联的每个文件都分配有一个唯一的编号以进行标识,称为文件描述符。 文件描述符: 0 是标准输入(stdin),1 是标准输出(stdout),2 是标准错误输出(stderr)。    输入/输出在没有重定向的情况下(默认情况),输出到终端,从终端接收输入。    重定向命令列表如下:

命令 描述
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag  将开始标记 tag 和结束标记 tag 之间的内容作为输入。

    1) 标准输出(stdout)重定向        重定向到 file,格式如下:            $ command > file            或            $ command 1> file         以追加方式重定向到 file,格式如下:            $ command >> file            或            $ command 1>> file         示例

            $ echo "重定向到 file,不指定文件描述符" > data.txt
            $ cat data.txt

                重定向到 file,不指定文件描述符

            $ echo "重定向到 file,指定文件描述符" 1> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符   

            $ echo "以追加方式重定向到 file,不指定文件描述符" >> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符
                以追加方式重定向到 file,不指定文件描述符

            $ echo "以追加方式重定向到 file,指定文件描述符" 1>> data.txt
            $ cat data.txt

                重定向到 file,指定文件描述符
                以追加方式重定向到 file,不指定文件描述符
                以追加方式重定向到 file,指定文件描述符

            注: “1>” 和 “1>>” 里的文件描述符 “1” 和 “>” 之间不能有空格,如果有空格,“1” 会被作为字符串处理,而不是作为文件描述符来处理。    2) 标准输入(stdin)重定向        格式如下:            $ command < file        示例

1             $ wc -l data.txt    # 统计 data.txt 文件的行数
2                 
3                 3 data.txt      # 文件里有 3 行,并显示文件名
4 
5             $ wc -l < data.txt
6 
7                 3               # 不显示文件名

    3) 标准输出和输入同时重定向            格式如下:            $ command < infile > outfile        示例

1             $ wc -l < data.txt > result.txt     # 统计 data.txt 文件的行数,把统计结果写到 result.txt
2             $ cat result.txt
3 
4                 3 

    4) 标准错误输出(stderr)重定向        重定向到 file,格式如下:            $ command 2> file        以追加方式重定向到 file,格式如下:            $ command 2>> file        将 stderr 和 stdout 合并后重定向到 file,格式如下:            $ command > file 2>&1        将 stderr 和 stdout 合并后重定向到 file,格式如下:            $ command >> file 2>&1        示例

 1             $ ls test.sh aaa.sh     # test.sh 存在,aaa.sh 不存在
 2 
 3                 ls: aaa.sh: No such file or directory
 4                 test.sh
 5 
 6             $ ls test.sh aaa.sh 2> error.txt
 7 
 8                 test.sh
 9 
10             $ cat error.txt
11 
12                 ls: aaa.sh: No such file or directory
13 
14             $ ls bbb.sh 2>> error.txt    # bbb.sh 不存在
15             $ cat error.txt
16 
17                 ls: aaa.sh: No such file or directory
18                 ls: bbb.sh: No such file or directory
19 
20 
21             $ ls test.sh aaa.sh > result.txt 2>&1
22             $ cat result.txt
23 
24                 ls: aaa.sh: No such file or directory
25                 test.sh
26             
27             $ ls test.sh bbb.sh >> result.txt 2>&1
28             $ cat result.txt
29 
30                 ls: aaa.sh: No such file or directory
31                 test.sh
32                 ls: bbb.sh: No such file or directory
33                 test.sh

             注:                              (1) “2>” 和 “2>>” 里的文件描述符 “2” 和 “>” 之间不能有空格,如果有空格,“2” 会被作为字符串处理,而不是作为文件描述符来处理。                (2) “2>&1” 是一个整体,中间不能有空格,“2” 和 “1” 的位置不能交换。    5) Here Document        Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。        格式如下:            command << delimiter                document            delimiter        它的作用是将两个 delimiter 之间的内容 (document) 作为输入传递给 command。        注:结尾的 delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的 delimiter 前后的空格会被忽略掉。        在命令行中通过 wc -l 命令计算 Here Document 的行数:

1             $ wc -l << EOF  # 按回车键,进入输入模式,输入 3 行
2             >Hello world
3             >Good 123
4             >www.test.com
5             >EOF       # 输入 EOF,按回车键,退出输入模式
6 
7             3          # 输出结果为 3 行

        也可以将 Here Document 用在脚本中,例如:

1             #!/bin/bash
2 
3             cat << EOF
4             Hello world
5             Good 123
6             www.test.com
7             EOF

        执行以上脚本,输出结果:            Hello world            Good 123            www.test.com    6) /dev/null 文件        如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:            $ command > /dev/null        /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到 “禁止输出” 的效果。        如果希望屏蔽 stdout 和 stderr,可以这样写:            $ command > /dev/null 2>&1            注:”2>&1″ 是一个整体,中间不能有空格,“2” 和 “1” 的位置不能交换。

3. 文件包含

    Shell 也可以包含外部脚本,可以方便的封装一些公用的代码作为一个独立的文件。    Shell 文件包含的语法格式如下:        . filename   # 注意点号(.)和文件名中间有一空格        或        source filename    创建两个 shell 脚本文件。        demo1.sh 代码如下:            #!/bin/bash            url=”http://www.test.com”        demo2.sh 代码如下:

1             #!/bin/bash
2 
3             # 使用 . 号来引用 demo1.sh 文件
4             . ./demo1.sh
5 
6             # 或者使用以下包含文件代码
7             # source ./demo1.sh
8 
9             echo "Website:$url"

    接下来为 demo2.sh 添加可执行权限并执行:        $ chmod +x demo2.sh         $ ./demo2.sh             Website:http://www.test.com        注:被包含的文件 demo1.sh 不需要可执行权限。