【shell笔记>脚本】创建和使用shell函数

来源: Linux命令行与shell脚本编程大全

博客地址,推荐电脑点

内容

  • 基本的脚本函数
  • 返回值
  • 在函数中使用变量
  • 数组变量和函数
  • 函数递归
  • 创建库
  • 在命令行上使用函数

我们可以将shell脚本代码放进函数中封装起来,这样就能在脚本中的任何地方多次使用它了。

下面我们来逐步了解如何创建自己的shell脚本函数并在应用中使用它们。

基本的脚本函数

函数是一个脚本代码块,我们可以为其命名并在代码中任何位置重用。要在脚本中使用该代码块,只要使用所起的函数名就行了。

创建函数

有两种格式可以创建函数。第一种格式是使用关键字function,后跟分配给该代码块的函数名。

funtion name{
    commands
}

name属性定义了赋予函数的唯一名称,commands是构成函数的一条或多条bash shell命令。

第二种格式更接近其他编程语言中定义函数的方式:

name() {
  commands
}

使用函数

要使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。

wsx@wsx:~/tmp$ cat test1
#!/bin/bash
# using a function in a script

function func1 {
    echo "This is an example of a function"
}

count=1
while [ $count -le 5 ]
do
  func1
  count=$[ $count + 1 ] 
done

echo "This is the end of the loop"
func1
echo "Now, this is the end of the script"

wsx@wsx:~/tmp$ ./test1
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is the end of the loop
This is an example of a function
Now, this is the end of the script

注意,定义函数名func1的后面一定要跟{有空格隔开,不然会报错。函数要先定义再使用,接触过编程的想必不陌生吧

返回值

bash shell会把函数当做一个小型脚本,运行结束时会返回一个退出状态码,有3种不同的方法来为函数生成退出状态码。

默认退出状态码

默认函数的退出状态码是函数中最后一条命令返回的退出状态码。我们可以使用标准变量$?在函数执行结束后确定函数的状态码。

wsx@wsx:~/tmp$ cat test2
#!/bin/bash
# testing the exit status of a function

func1() {
    echo "trying to display a non-existent file"
    ls -l badfile
}

echo "testing the function"
func1
echo "The exit status is: $?"
wsx@wsx:~/tmp$ ./test2
testing the function
trying to display a non-existent file
ls: 无法访问'badfile': 没有那个文件或目录
The exit status is: 2

函数的退出状态码是2,说明函数的最后一条命令没有成功运行。但你无法知道函数中其他命令中是否成功运行,我们来看看下面一个例子。

wsx@wsx:~/tmp$ cat test3
#!/bin/bash
# testing the exit status of a function

func1(){
    ls -l badfile
    echo "This was a test of a bad command"
}

echo "testing the function:"
func1
echo "The exit status is: $?"
wsx@wsx:~/tmp$ ./test3
testing the function:
ls: 无法访问'badfile': 没有那个文件或目录
This was a test of a bad command
The exit status is: 0

这次函数的退出状态码是0,尽管其中有一条命令没有正常运行。可见使用函数的默认退出状态码是很危险的,幸运的是,我们有几种办法解决它。

使用return命令

return命令允许指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来编码设定函数退出状态码。

wsx@wsx:~/tmp$ cat test4
#!/bin/bash
# using the return command in a function

function db1 {
    read -p "Enter a value: " value
    echo "doubling the value"
    return $[ $value * 2 ] 
}

db1
echo "The new value is $?"
wsx@wsx:~/tmp$ ./test4
Enter a value: 4
doubling the value
The new value is 8

当使用这种方法时要小心,记住下面两条技巧来避免问题:

  • 函数一结束就取返回值
  • 退出状态码必须是0~255

如果在用$?变量提取函数的返回值之前使用了其他命令,函数的返回值就会丢失。任何大于255的整数值都会产生一个错误值。

wsx@wsx:~/tmp$ ./test4
Enter a value: 200
doubling the value
The new value is 144

使用函数输出

如同可以将命令的输出保存到shell变量一样,我们也可以对函数的输出采用同样的处理办法。

result=`db1`

这个命令会将db1函数的输出赋值给$result变量。下面是脚本的一个实例:

wsx@wsx:~/tmp$ cat test4b
#!/bin/bash
# using the echo to return a value

function db1 {
    read -p "Enter a value: " value
    echo $[ $value * 2 ]
}

result=$(db1)
echo "The new value is $result"
wsx@wsx:~/tmp$ ./test4b
Enter a value: 200
The new value is 400

函数会用echo语句来显示计算的结果,该脚本会查看db1函数的输出,而不是查看退出状态码。

通过这种技术,我们还可以返回浮点值和字符串值,这使它成为一种获取函数返回值的强大方法。

在函数中使用变量

在函数中使用变量时,我们需要注意它们的定义方式以及处理方法。这是shell脚本常见错误的根源。

向函数传递参数

函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。例如,函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1$2定义。也可以用特殊变量$#来判断给函数的参数数目。

指定函数时,必须将参数和函数放在同一行:

func1 $value1 10

然后函数可以用参数环境变量来获得参数值。下面是一个例子:

wsx@wsx:~/tmp$ cat test5
#!/bin/bash
# passing parameters to a function

function addem {
    if [ $# -eq 0 ] || [ $# -gt 2 ]
    then
        echo -1
    elif [ $# -eq 1 ]
    then
        echo $[ $1 + $1 ]
    else
        echo $[ $1 + $2 ]
    fi
}

echo -n "Adding 10 and 15: "
value=$(addem 10 15)
echo $value
echo -n "Let's try adding just one number: "
value=$(addem 10)
echo $value
echo -n "Now trying adding no numbers: "
value=$(addem)
echo $value
echo -n "Finally, try add three numbers: "
value=$(addem 10 15 20)
echo $value
wsx@wsx:~/tmp$ ./test5
Adding 10 and 15: 25
Let's try adding just one number: 20
Now trying adding no numbers: -1
Finally, try add three numbers: -1

addem函数首先会检查脚本传给它的参数数目。如果没有任何参数,或者参数多于两个,addem会返回-1。如果只有一个参数,addem会将参数与自身相加。如果有两个参数,addem会将它们相加。

由于函数使用特殊参数环境变量作为自己的参数值,因此它无法直接获取脚本在命令行中的参数值。下面是个失败的例子:

wsx@wsx:~/tmp$ cat badtest1 
#!/bin/bash
# trying to access script parameters inside a function

function badfunc1 {
    echo $[ $1 * $2 ]
}

if [ $# -eq 2 ]
then
    value=$(badfunc1)
    echo "The result is $value"
else
    echo "Usage: badtest1 a b"
fi

wsx@wsx:~/tmp$ ./badtest1 10 15
./badtest1: 行 5: *  : 语法错误: 需要操作数 (错误符号是 "*  ")
The result is 

尽管函数也使用了$1$2变量,但它们与主脚本中的变量不同,要使用它们必须在调用函数时手动传入。

wsx@wsx:~/tmp$ cat test6
#!/bin/bash
# trying to access script parameters inside a function

function func1 {
    echo $[ $1 * $2 ]
}

if [ $# -eq 2 ]
then
    value=$(func1 $1 $2)
    echo "The result is $value"
else
    echo "Usage: badtest1 a b"
fi

wsx@wsx:~/tmp$ ./test6
Usage: badtest1 a b
wsx@wsx:~/tmp$ ./test6 10 15
The result is 150

在函数中处理变量

作用域是变量可见的区域。对脚本的其他部分而言,函数定义的变量是隐藏的。这些概念其实是编程语言中通用的,想必学过一些其他编程的朋友早已有所理解了。

函数使用两种类型的变量:

  • 全局变量
  • 局部变量

全局变量

全局变量是在shell脚本中任何地方都有效的变量,如果你在函数内定义了一个全局变量,也可以在脚本的主体部分读取它的值。

默认情况下,我们在脚本中定义的任何变量都是全局变量。

wsx@wsx:~/tmp$ cat test7
#!/bin/bash
# using a global variable to pass a value

function db1 {
    value=$[ $value * 2 ] 
}

read -p "Enter a value: " value
db1
echo "The new value is: $value"

wsx@wsx:~/tmp$ ./test7
Enter a value: 10
The new value is: 20

无论变量在函数内外定义,在脚本中引用该变量都有效。这样其实非常危险,尤其是如果你想在不同的shell脚本中使用函数的话。它要求你清清楚楚地知道函数中具体使用了哪些变量,包括那些用来计算非返回值的变量。下面是一个如何搞砸的例子:

wsx@wsx:~/tmp$ cat badtest2
#!/bin/bash
# demonstrating a bad use of variable

function func1 {
    temp=$[ $value + 5 ]
    result=$[ $temp * 2 ]
}

temp=4
value=6

func1
echo "The result is $result"
if [ $temp -gt $value ]
then
    echo "temp is larger"
else
    echo "temp is smaller"
fi
wsx@wsx:~/tmp$ ./badtest2
The result is 22
temp is larger

由于函数中用到了$temp变量,它的值在脚本中使用时受到了影响,产生了意想不到的后果。后面我们会学习如何处理这样的问题。

局部变量

无需在函数中使用全局变量,函数内部使用的任何变量都可以被声明成局部变量。我们只需要在变量声明前加上local关键字就可以了

local temp

也可以在变量赋值时使用local关键字:

local temp=$[ $value + 5 ]

local关键字保证了变量只局限于该函数中。我们再回看刚才的例子:

wsx@wsx:~/tmp$ cat test8
#!/bin/bash
# demonstrating the local keyword

function func1 {
    local temp=$[ $value + 5 ]
    result=$[ $temp * 2 ]
}

temp=4
value=6

func1
echo "The result is $result"
if [ $temp -gt $value ]
then
    echo "temp is larger"
else
    echo "temp is smaller"
fi

wsx@wsx:~/tmp$ ./test8
The result is 22
temp is smaller

数组变量和函数

在函数中使用数组变量值有点麻烦,还需要一些特殊考虑。下面我们使用一种方法来解决问题。

向函数传数组参数

这个方法有点不好理解,将数组变量当做单个参数传递的话不起作用,下面我们看一个bad例子:

wsx@wsx:~/tmp$ cat badtest3
#!/bin/bash
# trying to pass an array variable

function testit {
    echo "The parameters are: $@"
    thisarray=$1
    echo "The received array is ${thisarray[*]}"
}

myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit $myarray
wsx@wsx:~/tmp$ ./badtest3
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1

可以看到,当我们将数组变量当做函数参数传递时,函数只会取数组变量的第一个值。

针对这个问题,我们的一个解决方案是将数组变量全部拆分为单个值,然后作为参数传入函数,在函数内部又重新对这些值进行组装。

wsx@wsx:~/tmp$ cat test9
#!/bin/bash
# array variable to function test

function testit {
    local newarray
    newarray=(`echo "$@"`)
    echo "The new array value is: ${newarray[*]}"
}

myarray=(1 2 3 4 5)
echo ${myarray[*]}
testit ${myarray[*]}

wsx@wsx:~/tmp$ ./test9
1 2 3 4 5
The new array value is: 1 2 3 4 5

从函数中返回数组

采用与上面类似的方法,函数用echo语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。

wsx@wsx:~/tmp$ cat test10
#!/bin/bash
# returning an array value

function arraydblr {
    local origarray
    local newarray
    local elements
    local i
    origarray=($(echo "$@"))
    newarray=($(echo "$@"))
    elements=$[ $# - 1 ]
    for (( i = 0; i <= $elements; i++ ))
    {
        newarray[$i]=$[ ${origarray[$i]} * 2]
    }
    echo ${newarray[*]}
}

myarray=(1 2 3 4 5)
echo "The orignal array is ${myarray[*]}"
arg1=$(echo ${myarray[*]})
result=($(arraydblr $arg1))
echo "The new array is: ${result[*]}"

wsx@wsx:~/tmp$ ./test10
The orignal array is 1 2 3 4 5
The new array is: 2 4 6 8 10

该脚本用$arg1变量将数组值传给arraydblr函数。该函数将数组重组到新的数组变量中,生成输出数组变量的一个副本,然后对数据元素进行遍历,将每个元素值翻倍,并将结果存入函数中该数组变量的副本。

函数递归

局部函数变量的一个特征是自成体系。这个特性使得函数可以递归地调用,也就是函数可以调用自己来得到结果。通常递归函数都有一个最终可以迭代到的基准值。

递归算法的经典例子是计算阶乘:一个数的阶乘是该数之前的所有数乘以该数的值。

比如5的阶乘:

5! = 1 * 2 * 3 * 4 * 5

方程可以简化为通用形式:

x! = x * (x-1)!

这可以用简单的递归脚本表达为:

function factorial {
  if [ $1 -eq 1 ]
  then
    echo 1
  else
    local temp=$[ $1 - 1 ]
    local result=`factorial $temp`
    echo $[ $result * $1 ]
  fi
}

下面用它来进行计算:

wsx@wsx:~/tmp$ cat test11
#!/bin/bash
# using recursion

function factorial {
    if [ $1 -eq 1 ]
    then
        echo 1
    else
        local temp=$[ $1 - 1]
        local result=`factorial $temp`
        echo $[ $result * $1 ]
    fi
}

read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"

wsx@wsx:~/tmp$ ./test11
Enter value: 5
The factorial of 5 is: 120

创建库

如果你碰巧要在多个脚本中使用同一段代码呢?显然在每个脚本中都定义同样的函数太麻烦了,一种解决方法就是创建库文件,然后在脚本中引用它。

第一步是创建一个包含脚本中所需函数的公用库文件。下面是一个叫做myfuncs的库文件,定义了3个简单的函数。

wsx@wsx:~/tmp$ cat myfuncs
#!/bin/bash
# my script functions

function addem {
    echo $[ $1 + $2 ]
}

function multem {
    echo $[ $1 * $2 ]
}

function divem {
    if [ $2 -ne 0 ]
    then
        echo $[ $1 / $2 ]
    else
        echo -1
    fi
}

下一步是在用到这些函数的脚本文件中包含myfuncs库文件。

这里有点复杂,主要问题出在shell函数的作用域上。如果我们尝试像普通脚本一样运行库文件,函数不会出现在脚本中。

使用函数库的关键在于source命令。source命令会在当前shell上下文中执行命令,而不是创建一个新的shell。通过source命令就可以使用库中的函数了。

source命令有一个快捷别名,称为点操作符。要在shell脚本中运行myfuncs库文件,只需要使用下面这行:

. ./myfuncs

注意第一个点是点操作符,而第二个点指向当前目录(相对路径)。

下面这个例子假定myfuncs库文件与要使用它的脚本位于同一目录,不然需要使用相对应的路径进行访问。

wsx@wsx:~/tmp$ cat test12
#!/bin/bash
# using functions defined in a library file

. ./myfuncs

value1=10
value2=5
result1=$(addem $value1 $value2)
result2=$(multem $value1 $value2)
result3=$(divem $value1 $value2)
echo "The result of adding them is: $result1"
echo "The result of multiplying them is: $result2"
echo "The result of dividing them is: $result3"

运行:

wsx@wsx:~/tmp$ ./test12
The result of adding them is: 15
The result of multiplying them is: 50
The result of dividing them is: 2

在命令行上使用函数

有时候有必要在命令行界面的提示符下直接使用这些函数。这是个灰常不错的功能,在shell中定义的函数可以在整个系统中使用它,无需担心脚本是不是在PATH环境变量中。

重点在于让shell能够识别这些函数。以下有几种方法可以实现。

在命令行上创建函数

shell会解释用户输入的命令,所以可以在命令行上直接定义一个函数。

有两种方法。

一种是采用单行方式定义函数。

wsx@wsx:~/tmp$ function divem { echo $[ $1 / $2 ]; }
wsx@wsx:~/tmp$ divem 100 5
20

当在命令行上定义函数时,你必须记得在每个命令后面加个分号,这样shell能识别命令的起始。

另一种是采用多行方式来定义函数。在定义时bash shell会使用次提示符来提示输入更多命令。这种方法不必在命令末尾加分号,只要按回车键就可。

wsx@wsx:~/tmp$ function multem {
> echo $[ $1 * $2 ]
> }
wsx@wsx:~/tmp$ multem 2 5
10

注意:在命令行上创建函数不要跟内建命令重名,函数会覆盖原来的命令。

在.bashrc文件中定义函数

在bash shell每次启动时都会在主目录下查找.bashrc文件,不管是交互式shell还是shell中启动的新shell。所以我们可以将函数写入该文件,或者在脚本中写入命令读取函数文件。操作前面都讲过,不再赘述,只要把该文件当做脚本对待就可以了。理解这一点这部分就会了。

实例

在开源的世界里,共享代码才是关键,而这一点同样适用于脚本函数。我们可以下载大量各式各样的函数然后用于自己的应用程序。

这一节介绍如何下载、安装和使用GNU shtool shell脚本函数库。shtool库提供了一些简单的shell脚本函数,可以用来完成日常的shell功能。

下载和安装

shtool软件包下载地址:

http://mirrors.ustc.edu.cn/gnu/shtool/shtool-2.0.8.tar.gz # China

可以浏览器或者命令行下载:

wsx@wsx:~/tmp$ wget http://mirrors.ustc.edu.cn/gnu/shtool/shtool-2.0.8.tar.gz
--2017-11-24 00:34:32--  http://mirrors.ustc.edu.cn/gnu/shtool/shtool-2.0.8.tar.gz
正在解析主机 mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 202.141.176.110, 218.104.71.170, 2001:da8:d800:95::110
正在连接 mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|202.141.176.110|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度: 97033 (95K) [application/gzip]
正在保存至: “shtool-2.0.8.tar.gz”

shtool-2.0.8.tar.gz 100%[===================>]  94.76K  --.-KB/s    用时 0.1s  

2017-11-24 00:34:32 (783 KB/s) - 已保存 “shtool-2.0.8.tar.gz” [97033/97033])

复制到主目录,然后用tar命令提取文件:

wsx@wsx:~$ tar -zxvf shtool-2.0.8.tar.gz 
shtool-2.0.8/AUTHORS
shtool-2.0.8/COPYING
shtool-2.0.8/ChangeLog
shtool-2.0.8/INSTALL
shtool-2.0.8/Makefile.in
shtool-2.0.8/NEWS
shtool-2.0.8/RATIONAL
shtool-2.0.8/README
shtool-2.0.8/THANKS
shtool-2.0.8/VERSION
shtool-2.0.8/configure
shtool-2.0.8/configure.ac
shtool-2.0.8/sh.arx
shtool-2.0.8/sh.common
shtool-2.0.8/sh.echo
shtool-2.0.8/sh.fixperm
shtool-2.0.8/sh.install
shtool-2.0.8/sh.mdate
shtool-2.0.8/sh.mkdir
shtool-2.0.8/sh.mkln
shtool-2.0.8/sh.mkshadow
shtool-2.0.8/sh.move
shtool-2.0.8/sh.path
shtool-2.0.8/sh.platform
shtool-2.0.8/sh.prop
shtool-2.0.8/sh.rotate
shtool-2.0.8/sh.scpp
shtool-2.0.8/sh.slo
shtool-2.0.8/sh.subst
shtool-2.0.8/sh.table
shtool-2.0.8/sh.tarball
shtool-2.0.8/sh.version
shtool-2.0.8/shtool.m4
shtool-2.0.8/shtool.pod
shtool-2.0.8/shtool.spec
shtool-2.0.8/shtoolize.in
shtool-2.0.8/shtoolize.pod
shtool-2.0.8/test.db
shtool-2.0.8/test.sh

接下来可以构建shell脚本库文件了。

构建库

shtool文件必须针对特定的Linux环境进行配置。配置工作必须使用标准的configure和make命令

wsx@wsx:~$ cd shtool-2.0.8/
wsx@wsx:~/shtool-2.0.8$ ./configure
Configuring GNU shtool (Portable Shell Tool), version 2.0.8 (18-Jul-2008)
Copyright (c) 1994-2008 Ralf S. Engelschall <rse@engelschall.com>
checking whether make sets $(MAKE)... yes
checking for perl interpreter... /usr/bin/perl
checking for pod2man conversion tool... /usr/bin/pod2man
configure: creating ./config.status
config.status: creating Makefile
config.status: creating shtoolize
config.status: executing adjustment commands
wsx@wsx:~/shtool-2.0.8$ make
building program shtool
./shtoolize -o shtool all
Use of assignment to $[ is deprecated at ./shtoolize line 60.
Generating shtool...(echo 11808/12742 bytes)...(mdate 3695/4690 bytes)...(table 1818/2753 bytes)...(prop 1109/2038 bytes)...(move 2685/3614 bytes)...(install 4567/5495 bytes)...(mkdir 2904/3821 bytes)...(mkln 4429/5361 bytes)...(mkshadow 3260/4193 bytes)...(fixperm 1471/2403 bytes)...(rotate 13425/14331 bytes)...(tarball 5297/6214 bytes)...(subst 5255/6180 bytes)...(platform 21739/22662 bytes)...(arx 2401/3312 bytes)...(slo 4139/5066 bytes)...(scpp 6295/7206 bytes)...(version 10234/11160 bytes)...(path 4041/4952 bytes)
building manpage shtoolize.1
building manpage shtool.1
building manpage shtool-echo.1
building manpage shtool-mdate.1
shtool-mdate.tmp around line 222: You forgot a '=back' before '=head1'
POD document had syntax errors at /usr/bin/pod2man line 71.
building manpage shtool-table.1
building manpage shtool-prop.1
building manpage shtool-move.1
building manpage shtool-install.1
building manpage shtool-mkdir.1
shtool-mkdir.tmp around line 186: You forgot a '=back' before '=head1'
POD document had syntax errors at /usr/bin/pod2man line 71.
building manpage shtool-mkln.1
building manpage shtool-mkshadow.1
shtool-mkshadow.tmp around line 191: You forgot a '=back' before '=head1'
POD document had syntax errors at /usr/bin/pod2man line 71.
building manpage shtool-fixperm.1
building manpage shtool-rotate.1
building manpage shtool-tarball.1
building manpage shtool-subst.1
building manpage shtool-platform.1
building manpage shtool-arx.1
building manpage shtool-slo.1
building manpage shtool-scpp.1
building manpage shtool-version.1
building manpage shtool-path.1

configure命令会检查构建shtool库文件所必需的软件。一旦发现所需工具,它会使用工具路径修改配置文件。

make命令负责构建shtool库文件。最终的结果(shtool)是一个完整的库软件包。

我们可以测试下这个库文件:

wsx@wsx:~/shtool-2.0.8$ make test
Running test suite:
echo..........FAILED
+---Test------------------------------
| test ".`../shtool echo foo bar quux`" = ".foo bar quux" || exit 1
| bytes=`../shtool echo -n foo | wc -c | awk '{ printf("%s", $1); }'` || exit 1
| test ".$bytes" = .3 || exit 1
| bytes=`../shtool echo '\1' | wc -c | awk '{ printf("%s", $1); }'` || exit 1
| test ".$bytes" = .3 || exit 1
| exit 0
+---Trace-----------------------------
| + ../shtool echo foo bar quux
| + test .foo bar quux = .foo bar quux
| + ../shtool echo -n foo
| + wc -c
| + awk { printf("%s", $1); }
| + bytes=3
| + test .3 = .3
| + ../shtool echo \1
| + wc -c
| + awk { printf("%s", $1); }
| + bytes=2
| + test .2 = .3
| + exit 1
+-------------------------------------
mdate.........ok
table.........ok
prop..........ok
move..........ok
install.......ok
mkdir.........ok
mkln..........ok
mkshadow......ok
fixperm.......ok
rotate........ok
tarball.......ok
subst.........ok
platform......ok
arx...........ok
slo...........ok
scpp..........ok
version.......ok
path..........ok
FAILED: passed: 18/19, failed: 1/19

(有一个没通过~)

如果全部通过测试,就可以将库安装到系统中,这样所有脚本都能使用这个库了。

要完成安装,需要使用make命令的install选项。需要使用root权限。

wsx@wsx:~/shtool-2.0.8$ make install
./shtool mkdir -f -p -m 755 /usr/local
./shtool mkdir -f -p -m 755 /usr/local/bin
./shtool mkdir -f -p -m 755 /usr/local/share/man/man1
mkdir: cannot create directory '/usr/local/share/man/man1': Permission denied
chmod: cannot access '/usr/local/share/man/man1': No such file or directory
Makefile:94: recipe for target 'install' failed
make: *** [install] Error 1
wsx@wsx:~/shtool-2.0.8$ sudo make install
[sudo] wsx 的密码: 
./shtool mkdir -f -p -m 755 /usr/local
./shtool mkdir -f -p -m 755 /usr/local/bin
./shtool mkdir -f -p -m 755 /usr/local/share/man/man1
./shtool mkdir -f -p -m 755 /usr/local/share/aclocal
./shtool mkdir -f -p -m 755 /usr/local/share/shtool
./shtool install -c -m 755 shtool /usr/local/bin/shtool
./shtool install -c -m 755 shtoolize /usr/local/bin/shtoolize
./shtool install -c -m 644 shtoolize.1 /usr/local/share/man/man1/shtoolize.1
./shtool install -c -m 644 shtool.1 /usr/local/share/man/man1/shtool.1
./shtool install -c -m 644 shtool-echo.1 /usr/local/share/man/man1/shtool-echo.1
./shtool install -c -m 644 shtool-mdate.1 /usr/local/share/man/man1/shtool-mdate.1
./shtool install -c -m 644 shtool-table.1 /usr/local/share/man/man1/shtool-table.1
./shtool install -c -m 644 shtool-prop.1 /usr/local/share/man/man1/shtool-prop.1
./shtool install -c -m 644 shtool-move.1 /usr/local/share/man/man1/shtool-move.1
./shtool install -c -m 644 shtool-install.1 /usr/local/share/man/man1/shtool-install.1
./shtool install -c -m 644 shtool-mkdir.1 /usr/local/share/man/man1/shtool-mkdir.1
./shtool install -c -m 644 shtool-mkln.1 /usr/local/share/man/man1/shtool-mkln.1
./shtool install -c -m 644 shtool-mkshadow.1 /usr/local/share/man/man1/shtool-mkshadow.1
./shtool install -c -m 644 shtool-fixperm.1 /usr/local/share/man/man1/shtool-fixperm.1
./shtool install -c -m 644 shtool-rotate.1 /usr/local/share/man/man1/shtool-rotate.1
./shtool install -c -m 644 shtool-tarball.1 /usr/local/share/man/man1/shtool-tarball.1
./shtool install -c -m 644 shtool-subst.1 /usr/local/share/man/man1/shtool-subst.1
./shtool install -c -m 644 shtool-platform.1 /usr/local/share/man/man1/shtool-platform.1
./shtool install -c -m 644 shtool-arx.1 /usr/local/share/man/man1/shtool-arx.1
./shtool install -c -m 644 shtool-slo.1 /usr/local/share/man/man1/shtool-slo.1
./shtool install -c -m 644 shtool-scpp.1 /usr/local/share/man/man1/shtool-scpp.1
./shtool install -c -m 644 shtool-version.1 /usr/local/share/man/man1/shtool-version.1
./shtool install -c -m 644 shtool-path.1 /usr/local/share/man/man1/shtool-path.1
./shtool install -c -m 644 shtool.m4 /usr/local/share/aclocal/shtool.m4
./shtool install -c -m 644 sh.common /usr/local/share/shtool/sh.common
./shtool install -c -m 644 sh.echo /usr/local/share/shtool/sh.echo
./shtool install -c -m 644 sh.mdate /usr/local/share/shtool/sh.mdate
./shtool install -c -m 644 sh.table /usr/local/share/shtool/sh.table
./shtool install -c -m 644 sh.prop /usr/local/share/shtool/sh.prop
./shtool install -c -m 644 sh.move /usr/local/share/shtool/sh.move
./shtool install -c -m 644 sh.install /usr/local/share/shtool/sh.install
./shtool install -c -m 644 sh.mkdir /usr/local/share/shtool/sh.mkdir
./shtool install -c -m 644 sh.mkln /usr/local/share/shtool/sh.mkln
./shtool install -c -m 644 sh.mkshadow /usr/local/share/shtool/sh.mkshadow
./shtool install -c -m 644 sh.fixperm /usr/local/share/shtool/sh.fixperm
./shtool install -c -m 644 sh.rotate /usr/local/share/shtool/sh.rotate
./shtool install -c -m 644 sh.tarball /usr/local/share/shtool/sh.tarball
./shtool install -c -m 644 sh.subst /usr/local/share/shtool/sh.subst
./shtool install -c -m 644 sh.platform /usr/local/share/shtool/sh.platform
./shtool install -c -m 644 sh.arx /usr/local/share/shtool/sh.arx
./shtool install -c -m 644 sh.slo /usr/local/share/shtool/sh.slo
./shtool install -c -m 644 sh.scpp /usr/local/share/shtool/sh.scpp
./shtool install -c -m 644 sh.version /usr/local/share/shtool/sh.version
./shtool install -c -m 644 sh.path /usr/local/share/shtool/sh.path

现在我们能在自己的shell脚本中使用这些函数咯。

shtool库函数

函数描述
Arx创建归档文件(包含一些扩展功能)
Echo显示字符串,并提供了一些扩展构件
fixperm改变目录树的文件权限
install安装脚本或文件
mdate显示文件或目录修改时间
mkdir创建一个或更多目录
Mkln使用相对路径创建链接
mkshadow创建一棵阴影树
move带有替换功能的文件移动
Path处理程序路径
platform显示平台标识
Prop显示一个带有动画效果的进度条
rotate转置日志文件
Scpp共享的C预处理器
Slo根据库的类别,分离链接器选项
Subst使用sed的替换操作
Table以表格的形式显示由字段分隔的数据
tarball从文件和目录中创建tar文件
version创建版本信息文件

每个shtool函数都包含大量的选项和参数。下面是使用格式:

shtool [option] [function [option] [args]]

使用库

我们能直接在命令行或者在自己构建的脚本中使用shtool的函数。

下面是在脚本中使用的简单例子:

wsx@wsx:~/tmp$ cat test13
#!/bin/bash
shtool platform
wsx@wsx:~/tmp$ ./test13
Ubuntu 17.10 (AMD64)

platform函数会返回Linux发行版以及系统使用的CPU硬件相关信息。

prop函数可以使用\,|,/-字符创建一个旋转的进度条。它可以告诉shell脚本用户目前正在处理一些后台处理工作。

wsx@wsx:~/tmp$ ls -al /usr/bin | shtool prop -p "waiting..."
waiting...

在脚本学习中涉及到诸多的符号,在运行时我们可能会感觉到顺利,但自己写的时候往往会用不太对,推荐阅读一下常用的一些符号区分,像小括号、中括号、花括号等等。觉的不懂的可以看看Linux_Bash脚本_单引号’双引号“”反引号`小括号()中括号[]大括号{}以及相关的百度资料。

点赞