shell编程 - 位置参数

位置参数

        之前一直没有涉及程序接收和处理命令行选项及实参的能力,本节将介绍程序访问命令行内容的shell功能

访问命令行

        shell提供了一组名为位置参数的变量,用于存储命令行中的关键字,这些变量分别命名0~9,可以通过以下方式访问这些变量

#!/bin/bash

# posit-param:script to view command line parameters

echo "
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
"

在没有任何命令行实参的情形下执行此脚本,运行结果如下

$0 = a.sh
$1 = 
$2 = 
$3 = 
$4 = 
$5 = 
$6 = 
$7 = 
$8 = 
$9 = 

可以看到,即便没有任何的命令行实参,变量$0总是会存储所执行程序所在的文件名

!!!使用参数扩展技术,用户实际可以获取多于9个的位置参数,为标明一个大于9的数字,需要将数字用大括号括起来,例如${10}、${56}、${256}

确定实参的数目

shell还提供了变量 $# 以给出命令行参数的个数。

#!/bin/bash

# posit-param:script to view command line parameters

echo "
Number of arguments:$#
\$0 = $0
\$1 = $1
\$2 = $2
\$3 = $3
\$4 = $4
\$5 = $5
\$6 = $6
\$7 = $7
\$8 = $8
\$9 = $9
\$10 = ${10}
"

($0 :表示执行脚本名称;$# :表示命令行参数个数)

shift——处理大量的实参

#!/bin/bash

# posit-param2:script to display all arguments

count=1

while [[ $# -gt 0 ]];do
        echo "Argument $count: $1"
        count=$((count+1))
        shift
done

        shift提供了一种机制,每次执行shift命令后,所有的参数值均“下移一位”。即变量$2的值会赋给变量$1,而$3的值则会赋给变量$2,以此类推,全部“下移一位”,并且变量$#的值同时减1。

        通过shift命令,我们只需要处理一个参数即可,即$1。

        以上脚本,创建了一个循环,只要还存在1个实参,循环就不停止。首先输出当前的实参,其次,每次循环迭代一次,就将变量count值加1,代表处理过的实参数目。最后,执行shift命令使得$1载入下一个实参的值。

一个简单的应用程序

#!/bin/bash

# file_info:simple file information program

PROGNAME=$(basename $0)
while [[ $# -gt 0 ]];do
if [[ -e $1 ]];then
        echo -e "\nFile Type:"
        file $1
        echo -e "\nFile Status:"
        stat $1
else
        echo "$PROGNAME: usage:$PROGNAME file" >&2
        exit 1
fi
shift
done

列出指令路径下实参(路径下的各类文件)的文件类型(file命令)和文件状态(stat命令)。

在shell函数中使用位置参数

        如同位置参数可以向脚本传递实参一样,位置参数也可以用于shell函数实参的传递

file_info(){
    # file_info:functiono to display file information
    if [[ -e $1 ]];then
        echo -e "\nFile Type:"
        file $1
        echo -e "\nFile Status:"
        stat $1
    else
        echo "$FUNCNAME: usage: $FUNCNAME file" >&2
        return 1
    fi
}

        函数的返回状态用return,如果不是函数则用exit命令。  tips

        我们不仅可以在普通脚本中传递位置参数给函数,也可以在.bashrc文件中维护使用位置参数的函数。

        需要注意的是,PROGNAME变量被换成了名为FUNCNAME的shell变量。shell会自动更新FUNCNAME以追踪当前执行的shell函数。

        $0变量表示的是执行脚本的脚本文件名称;$FUNCNAME变量用于函数中,表示的是所在函数的名称。注意区别。

处理多个位置参数

        有时候我们会把所有位置参数当做一个整体来处理。

shell为这项功能提供了两种特殊的参数。两种参数都能扩展为一个完整的位置参数列,但是又有着微妙的区别。

参数描述
$*可扩展为从1开始的位置参数列。当包括在双引号内时,扩展为双引号引用的由全部位置参数构成的字符串,每个位置参数以IFS shell变量的第一个字符(默认情况下为空格)间隔开
$@可扩展为从1开始的位置参数列。当包含在双引号内时,将每个位置参数扩展为双引号引用的单独单词
#!/bin/bash

# posit-params3:script to demonstrate $* and $@

print_params(){
        echo "\$1 = $1"
        echo "\$2 = $2"
        echo "\$3 = $3"
        echo "\$4 = $4"
}

pass_params(){
        echo -e "\n" '$* :';print_params $*
        echo -e "\n" '"$*" :';print_params "$*"
        echo -e "\n" '$@ :';print_params $@
        echo -e "\n" '"$@" :';print_params "$@"
}

pass_params "word" "words with spaces"

执行结果


 $* :
$1 = word
$2 = words
$3 = with
$4 = spaces

 "$*" :
$1 = word words with spaces
$2 = 
$3 = 
$4 = 

 $@ :
$1 = word
$2 = words
$3 = with
$4 = spaces

 "$@" :
$1 = word
$2 = words with spaces
$3 = 
$4 = 

"$*" 和 "$@" 都产生了包含4个单词的结果。"$*"产生的是只包含一条字符串的结果,即word words with spaces。"$@"产生的则是包含了两条字符串的结果,即word和words with spaces。

        因为"$@"保持了每个位置参数的完整性,没有破坏位置参数的结构,所以"$@"是大多数情况下的使用格式!

更完整的应用程序

        在位置参数的帮助下,用户可以写出功能性更强的脚本。通常,对于重复性的任务,位置参数使得用户可以写出很有帮助的shell函数,并放置在用户的.bashrc文件中。

        回到系统信息报告生成器脚本,如下

#!/bin/bash

# sys_info_page: program to output a system information page

PROGNAME=$(basename $0)
TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME ,by $USER"

report_uptime () {
        cat <<- _EOF_
                <H2>System Uptime</H2>
                <PRE>$(uptime)</PRE>
                _EOF_
        return
}
report_disk_space () {
        cat <<- _EOF_
                <H2>Disk Space Utilization</H2>
                <PRE>$(df -h)</PRE>
                _EOF_
        return
}
report_home_space () {
        if [[ $(id -u) -eq 0 ]];then
                cat <<- _EOF_
                        <H2>Home Space Utilization(All Users)</H2>
                        <PRE>$(du -sh /home/*)</PRE>
                        _EOF_
        else
                cat <<- _EOF_
                        <H2>Home Space Utilization ($USER)</H2>
                        <PRE>$(du -sh $HOME)</PRE>
                        _EOF_
        fi
        return
}

usage () {
        echo "$PROGNAME: usage: $PROGNAME [-f file| -i ]"
        return
}

write_html_page () {
        cat <<- _EOF_
                <HTML>
                        <HEAD>
                                <TITLE>$TITLE</TITLE>
                        </HEAD>
                        <BODY>
                                <H1>$TITLE</H1>
                                <P>$TIME_STAMP</P>
                                $(report_uptime)
                                $(report_disk_space)
                                $(report_home_space)
                        </BODY>
                </HTML>
                _EOF_
        return
}

# process command line option

interactive=
filename=

while [[ -n $1 ]];do
        case $1 in
                -f | --file)    shift
                                filename=$1
                                ;;
                -i | --interactive)     interactive=1
                                        ;;
                -h | --help)    usage
                                exit
                                ;;
                *)      usage >&2
                        exit 1
                        ;;
        esac
        shift
done

# interactive mode
if [[ -n $interactive ]];then
        while true;do
                read -p "Enter name of output file: " filename
                if [[ -e $filename ]];then
                        read -p "'$filename' exists. Overwrite? [y/n/q] > "
                        case $REPLY in
                                Y|y)    break
                                        ;;
                                Q|q)    echo "Program terminated."
                                        exit
                                        ;;
                                *)      continue
                                        ;;
                        esac
                elif [[ -z $filename ]];then
                        continue
                else
                        break
                fi
        done
fi

# output html page

if [[ -n $filename ]];then
        if touch $filename && [[ -f $filename ]];then
                write_html_page > $filename
        else
                echo "$PROGNAME:Cannot write file '$filename'" >&2
                exit 1
        fi
else
        write_html_page
fi

需要多看以上脚本,理解与学习其编写脚本的设计思想。


可以关注作者微信公众号,追踪更多有价值的内容!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值