《linux命令行与shell脚本编程大全》第三版

来源:互联网 发布:秦时明月知乎 编辑:程序博客网 时间:2024/06/05 14:55
《linux命令行与shell脚本编程大全》
全书4部分:
☆ 【1】linux命令行(1-10章)
☆ 【2】shell脚本编程基础(11-16章)
☆ 【3】高级shell脚本编程(17-23章):函数与图形化脚本
☆ 【4】创建实用的脚本(24-26章)

>>第17章丶创建函数

函数-调用格式
function name {
    commands
}

// 函数名必须是唯一的。如果重复定义会覆盖第一个,并且不会提示错误。
在bash shell脚本中定义函数的第二种格式更接近于其他编程语言中定义函数的方式。
name() {
    commands
}

要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。
bash shell会把函数当作一个小型脚本,运行结束时会返回一个退出状态码。
可以用标准变量$?来确定函数的退出状态码。
/* 演示 */#!/bin/bash# testing the exit status of a functionfunc1() {    echo "trying to display a non-existent file"    ls -l badfile}echo "testing the function: "func1echo "The exit status is: $?"
$:' ./test1.sh
testing the function:
trying to display a non-existent file
ls: badfile: No such file or directory
The exit status is: 1
// 函数的退出状态码是1,这是因为函数中的最后一条命令没有成功运行。但你无法知道函数中其他命令中是否成功运行。

return

bash shell使用return命令来退出函数并返回特定的退出状态码。
/* 演示 */#!/bin/bash# using the return command in a functionfunction dbl {    read -p "Enter a value: " value    echo "doubling the value"    return $[ $value * 2 ]}dblecho "The new value is $?"
$: test.sh
Enter a value: 111
doubling the value
The new value is 222

两条技巧来避免问题:
 记住,函数一结束就取返回值;
 记住,退出状态码必须是0~255。


使用函数的输出

/* 演示 */#!/bin/bash# using the echo to return a valuefunction dbl {    read -p "Enter a value: " value    echo $[ $value * 2 ]}result=$(dbl)echo "The new value is $result"
$: test.sh
Enter a value: 111
The new value is 222

在函数中使用变量

函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。例如,函数名会在$0变量中定义,函数命令行上的任何参数都会通过$1、 $2等定义。也可以用特殊变量$#来判断传给函数的参数数目。
/* 向函数传值演示 */#!/bin/bash# passing parameters to a functionfunction addem {if [ $# -eq 0 ] || [ $# -gt 2 ] ; thenecho -1    elif [ $# -eq 1 ] ; thenecho $[ $1 + $1 ]elseecho $[ $1 + $2 ]fi}echo -n "Adding 10 and 15: "value=$(addem 10 15)echo $valueecho -n "Let's try adding just one number: "value=$(addem 10)echo $valueecho -n "Now trying adding no numbers: "value=$(addem)echo $valueecho -n "Finally, try adding three numbers: "value=$(addem 10 15 20)echo $value
$: test.sh
Adding 10 and 15: 25
Let's try adding just one number: 20
Now trying adding no numbers: -1
Finally, try adding three numbers: -1

传递命令行中的参数到脚本函数中,需要手动传递:
/* 伪代码演示 */function func7 {    echo $[ $1 * $2 ]}if [ $# -eq 2 ]then    value=$(func7 $1 $2)    echo "The result is $value"else    echo "Usage: badtest1 a b"fi
默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问。
local

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

向函数传数组参数

必须将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。在函数内部,可以将所有的参数重新组合成一个新的变量。
/* 演示 */#!/bin/bash# test array variable to functionfunction testit {    local newarray    newarray=(`echo "$@"`)    echo "The new array value is: ${newarray[*]}"}myarray=(1 2 3  4 5)echo "The original array is ${myarray[*]}"testit ${myarray[*]}
$: test.sh
The original array is 1 2 3 4 5
The new array value is: 1 2 3 4 5
// 用$myarray变量来保存所有的数组元素,然后将它们都放在函数的命令行上。该函数随后从命令行参数中重建数组变量。在函数内部,数组仍然可以像其他数组一样使用。
/* 遍历数组元素 */#!/bin/bash# adding values in an arrayfunction addarray {local sum=0local newarraynewarray=($(echo "$@"))for value in ${newarray[*]}dosum=$[ $sum + $value ]doneecho $sum}myarray=(1 2 3 4 5)echo "The original array is: ${myarray[*]}"arg1=$(echo ${myarray[*]})result=$(addarray $arg1)echo "The result is $result"
$: test.sh
The original array is: 1 2 3 4 5
The result is 15

从函数返回数组

从函数里向shell脚本传回数组变量也用类似的方法。函数用echo语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。
/* 函数返回数组演示 */#!/bin/bash# returning an array valuefunction arraydblr {local origarraylocal newarraylocal elementslocal iorigarray=($(echo "$@"))newarray=($(echo "$@"))elements=$[ $# - 1 ]for (( i = 0; i <= $elements; i++ )){newarray[$i]=$[ ${origarray[$i]} * 2 ]}echo ${newarray[*]}    echo "test.."}myarray=(1 2 3 4 5)echo "The original array is: ${myarray[*]}"arg1=$(echo ${myarray[*]})result=($(arraydblr $arg1))echo "The new array is: ${result[*]}"
$: test.sh
The original array is: 1 2 3 4 5
The new array is: 2 4 6 8 10 test..

函数递归

/* 演示 */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}

创建函数库

source

使用函数库的关键在于source命令。 source命令会在当前shell上下文中执行命令,而不是创建一个新shell。
source命令有个快捷的别名,称作点操作符 . (dot operator)。
/* 演示 myfunc.sh */# my script functionsfunction addem {    echo $[ $1 + $2 ]}function multem {    echo $[ $1 * $2 ]}function divem {    if [ $2 -ne 0 ]    then        echo $[ $1 / $2 ]    else        echo -1    fi}
/* 演示 test.sh */#!/bin/bash# using functions defined in a library file#source ./myfuncs.sh. ./myfuncs.shvalue1=10value2=5result1=$(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"
$ ./test.sh
The result of adding them is: 15
The result of multiplying them is: 50
The result of dividing them is: 2

在命令行上创建函数
一种方法是采用单行方式定义函数。
$ function divem { echo $[ $1 / $2 ]; }
$ divem 100 5
20
另一种方法是采用多行方式来定义函数。在定义时, bash shell会使用次提示符来提示输入更多命令。用这种方法,你不用在每条命令的末尾放一个分号,只要按下回车键就行。
$ function multem {
  > echo $[ $1 * $2 ]
  > }
$ multem 2 5
10
[警告]在命令行上创建函数时要特别小心。如果你给函数起了个跟内建命令或另一个命令相同的名字,函数将会覆盖原来的命令。

在~/.bashrc 文件中定义函数:
在命令行上直接定义shell函数的明显缺点是退出shell时,函数就消失了。
一个非常简单的方法是将函数定义在一个特定的位置,这个位置在每次启动一个新shell的时候,都会由shell重新载入。最佳地点就是.bashrc文件。
举例(略)。

shtool脚本函数库

/* 【实例】下载、安装、使用GNU shtool shell脚本函数库 */
shtool库提供了一些简单的shell脚本函数,可以用来完成日常的shell功能,例如处理临时文件和目录或者格式化输出显示。
1.下载及安装:
ftp://ftp.gnu.org/gnu/shtool/shtool-2.0.8.tar.gz
$:' tar -zxvf shtool-2.0.8.tar.gz
2.构建库:
$:' ./configure
$:' make
// shtool文件必须针对特定的Linux环境进行配置。
$:' make test
// 测试库文件,都ok以后进行下一步
$:' su
#:' make install
// root用户身份进行将库安装到linux系统的公用位置,现在就可以在shell中使用这些函数了

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


shtool函数的使用格式
    shtool [options] [function [options] [args]]

platform函数会返回Linux发行版以及系统所使用的CPU硬件的相关信息。我喜欢的一个函数prop函数。它可以使用\、 |、 /和-字符创建一个旋转的进度条。这是一个非常漂亮的工具,可以告诉shell脚本用户目前正在进行一些后台处理工作。
要使用prop函数,只需要将希望监看的输出管接到shtool脚本就行了。
$ ls –al /usr/bin | shtool prop –p "waiting..."
waiting...

>>第18章丶图形化桌面环境中的脚本编程


1.创建文本菜单

shell脚本菜单的核心是case命令。
clear命令用当前终端会话的terminfo数据来清理出现在屏幕上的文本。

2.创建菜单函数

通常我们会为还没有实现的函数先创建一个桩函数(stub function)。桩函数是一个空函数,或者只有一个echo语句,说明最终这里里需要什么内容。
/* 桩函数 */
function diskspace {
    clear
    echo "This is where the diskspace commands will go"
}

将菜单布局本身作为一个函数来创建,任何时候都能随时重现菜单:
/* 菜单函数,用于重现 */
function menu {
    clear
    echo
    echo -e "\t\t\tSys Admin Menu\n"
    echo -e "\t1. Display disk space"
    echo -e "\t2. Display logged on users"
    echo -e "\t3. Display memory usage"
    echo -e "\t0. Exit program\n\n"
    echo -en "\t\tEnter option: "
    read -n 1 option
}

3.添加菜单逻辑

/* 菜单逻辑伪代码脚本 */
#function
menu
case $option in
    0)
        break ;;
    1)
        diskspace ;;
    2)
        whoseon ;;
    3)
        memusage ;;
    *)
    clear
    echo "Sorry, wrong selection";;
esac


shell脚本菜单框架

/* shell脚本菜单完整脚本代码框架 */#!/bin/bash# simple script menufunction diskspace {    clear    df -k}function whoseon {    clear    who}function memusage {    clear    cat /proc/meminfo}function menu {    clear    echo    echo -e "\t\t\tSys Admin Menu\n"    echo -e "\t1. Display disk space"    echo -e "\t2. Display logged on users"    echo -e "\t3. Display memory usage"    echo -e "\t0. Exit program\n\n"    echo -en "\t\tEnter option: "    read -n 1 option}while [ 1 ]do    menu    case $option in    q)        break ;;    1)        diskspace ;;    2)        whoseon ;;    3)        memusage ;;    *)        clear        echo "Sorry, wrong selection";;    esac    echo -en "\n\t\t\tHit any key to continue"    read -n 1 linedoneclear
/*****************************************************************/
Sys Admin Menu

1. Display disk space
2. Display logged on users
3. Display memory usage
0. Exit program

Enter option:
/*****************************************************************/

select

select命令只需要一条命令就可以创建出菜单,然后获取输入的答案并自动处理。 select命令的格式如下。
select variable in list
do
    commands
done

//list参数是由空格分隔的文本选项列表,这些列表构成了整个菜单。
/* select命令示例 */#!/bin/bash# using select in the menufunction diskspace {    clear    df -k}function whoseon {    clear    who}function memusage {    clear    cat /proc/meminfo}PS3="Enter option: "select option in "Display disk space" "Display logged on users" "Display memory usage" "Exit program"do    case $option in    "Exit program")        break ;;    "Display disk space")        diskspace ;;    "Display logged on users")        whoseon ;;    "Display memory usage")        memusage ;;    *)        clear        echo "Sorry, wrong selection";;    esacdoneclear
/*****************************************************************/
$: test.sh
1) Display disk space    3) Display memory usage
2) Display logged on users  4) Exit program
Enter option:
/*****************************************************************/

4.制作窗口:

$:' sudo apt-get install dialog
这条命令将会为你的系统安装dialog包以及需要的库。
dialog部件:
calendar 提供选择日期的日历
checklist 显示多个选项(其中每个选项都能打开或关闭)
form 构建一个带有标签以及文本字段(可以填写内容)的表单
fselect 提供一个文件选择窗口来浏览选择文件
gauge 显示完成的百分比进度条
infobox 显示一条消息,但不用等待回应
inputbox 提供一个输入文本用的文本表单
inputmenu 提供一个可编辑的菜单
menu 显示可选择的一系列选项
msgbox 显示一条消息,并要求用户选择OK按钮
pause 显示一个进度条来显示暂定期间的状态
passwordbox 显示一个文本框,但会隐藏输入的文本
passwordform 显示一个带标签和隐藏文本字段的表单
radiolist 提供一组菜单选项,但只能选择其中一个
tailbox 用tail命令在滚动窗口中显示文件的内容
tailboxbg 跟tailbox一样,但是在后台模式中运行
textbox 在滚动窗口中显示文件的内容
timebox 提供一个选择小时、分钟和秒数的窗口
yesno 提供一条带有Yes和No按钮的简单消息


dialog命令行格式:
dialog --widget parameters
其中widget是表18-1中的部件名, parameters定义了部件窗口的大小以及部件需要的文本。每个dialog部件都提供了两种形式的输出:
 使用STDERR
 使用退出状态码

可以通过dialog命令的退出状态码来确定用户选择的按钮。如果选择了Yes或OK按钮,dialog命令会返回退出状态码0。如果选择了Cancel或No按钮,dialog命令会返回退出状态码1。可以用标准的$?变量来确定dialog部件中具体选择了哪个按钮。

magbox
该部件会在窗口中显示一条简单的消息,直到用户单击OK按钮后才消失。格式:
    dialog --msgbox text height width
// text参数是你想在窗口中显示的字符串。 dialog命令会根据由height和width参数创建的窗口的大小来自动换行。如果想在窗口顶部放一个标题,也可以用--title参数,后接作为标题的文本。
例子:$ dialog --title Testing --msgbox "This is a test" 10 20

yesno
该部件允许用户对窗口中显示的问题选择yes或no。
例子:
$ dialog --title "Please answer" --yesno "Is this thing on?" 10 20
$ echo $?
1

inputbox
该部件为用户提供了一个简单的文本框区域来输入文本字符串。
dialog命令会将文本字符串的值发给STDERR。你必须重定向STDERR来获取用户输入。
如果选择了OK按钮,命令的退出状态码就是0;反之,退出状态码就会是1。
$ dialog --inputbox "Enter your age:" 10 20 2>age.txt
$ echo $?
0
$ cat age.txt
12

textbox
该部件是在窗口中显示大量信息的极佳办法。它会生成一个滚动窗口来显示由参数所指定的文件中的文本。
$ dialog --textbox /etc/passwd 15 45

menu
该部件允许你来创建我们之前所制作的文本菜单的窗口版本。
$ dialog --menu "Sys Admin Menu" 20 30 10 1 "Display disk space" 2 "Display users" 3 "Display memory usage" 4 "Exit" 2> test.txt

fselect
fselect部件在处理文件名时非常方便。不用强制用户键入文件名,你就可以用fselect部件来浏览文件的位置并选择文件。
$ dialog --title "Select a file" --fselect $HOME/ 10 50 2>file.txt

dialog命令选项:
--add-widget            继续下个对话框,直到按下Esc或Cancel按钮--aspect ratio          指定窗口宽度和高度的宽高比--backtitle title       指定显示在屏幕顶部背景上的标题--begin x y             指定窗口左上角的起始位置--cancel-label label    指定Cancel按钮的替代标签--clear                 用默认的对话背景色来清空屏幕内容--colors                在对话文本中嵌入ANSI色彩编码--cr-wrap               在对话文本中允许使用换行符并强制换行--create-rc file        将示例配置文件的内容复制到指定的file文件中①--defaultno             将yes/no对话框的默认答案设为No--default-item string   设定复选列表、表单或菜单对话中的默认项--exit-label label      指定Exit按钮的替代标签--extra-button          在OK按钮和Cancel按钮之间显示一个额外按钮--extra-label label     指定额外按钮的替代标签--help                  显示dialog命令的帮助信息--help-button           在OK按钮和Cancel按钮后显示一个Help按钮--help-label label      指定Help按钮的替代标签--help-status           当选定Help按钮后,在帮助信息后写入多选列表、单选列表或表单信息--ignore                忽略dialog不能识别的选项--input-fd fd           指定STDIN之外的另一个文件描述符--insecure              在password部件中键入内容时显示星号--item-help             为多选列表、单选列表或菜单中的每个标号在屏幕的底部添加一个帮助栏--keep-window           不要清除屏幕上显示过的部件--max-input size        指定输入的最大字符串长度。默认为2048--nocancel              隐藏Cancel按钮--no-collapse           不要将对话文本中的制表符转换成空格--no-kill               将tailboxbg对话放到后台,并禁止该进程的SIGHUP信号--no-label label        为No按钮指定替代标签--no-shadow             不要显示对话窗口的阴影效果--ok-label label        指定OK按钮的替代标签--output-fd fd          指定除STDERR之外的另一个输出文件描述符--print-maxsize         将对话窗口的最大尺寸打印到输出中--print-size            将每个对话窗口的大小打印到输出中--print-version         将dialog的版本号打印到输出中--separate-output       一次一行地输出checklist部件的结果,不使用引号--separator string      指定用于分隔部件输出的字符串--separate-widget string 指定用于分隔部件输出的字符串--shadow                在每个窗口的右下角绘制阴影--single-quoted         需要时对多选列表的输出采用单引号--sleep sec             在处理完对话窗口之后延迟指定的秒数--stderr                将输出发送到STDERR(默认行为)--stdout                将输出发送到STDOUT--tab-correct           将制表符转换成空格--tab-len n             指定一个制表符占用的空格数(默认为8)--timeout sec           指定无用户输入时, sec秒后退出并返回错误代码--title title           指定对话窗口的标题--trim                  从对话文本中删除前导空格和换行符--visit-items           修改对话窗口中制表符的停留位置,使其包括选项列表--yes-label label       为Yes按钮指定替代标签

在脚本中使用dialog命令不过就是动动手的事。你必须记住两件事:
 如果有Cancel或No按钮,检查dialog命令的退出状态码;
 重定向STDERR来获得输出值。

dialog命令实现shell脚本菜单框架

/* 使用dialog命令实现shell脚本菜单框架 */#!/bin/bash# using dialog to create a menutemp=$(mktemp -t test.XXXXXX)temp2=$(mktemp -t test2.XXXXXX)function diskspace {df -k > $tempdialog --textbox $temp 20 60}function whoseon {who > $tempdialog --textbox $temp 20 50}function memusage {cat /proc/meminfo > $tempdialog --textbox $temp 20 50}while [ 1 ]dodialog --menu "Sys Admin Menu" 20 30 10 1 "Display disk space" 2 "Display users" 3 "Display memory usage" 0 "Exit" 2> $temp2if [ $? -eq 1 ]thenbreakfiselection=$(cat $temp2)case $selection in1) diskspace ;;2) whoseon ;;3) memusage ;;0) break ;;*) dialog --msgbox "Sorry, invalid selection" 10 30esacdonerm -f $temp 2> /dev/nullrm -f $temp2 2> /dev/null

使用图形:
KDE(kdialog) --需要时扩展
GNOME(gdialog,zenity)  --需要时扩展




2017.06.25
第17章、18章完...(本部分需要逐章消化)未完待续!
阅读全文
0 0
原创粉丝点击