:变量和参数介绍
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:变量和参数介绍相关的知识,希望对你有一定的参考价值。
原文:http://shouce.jb51.net/shell/
linux shell编程、bash编程、shell教程、bash教程、shell文档、bash文档、shell脚本、bash脚本【教程】第一章:Shell编程 第二章:Sha-Bang(#!)开始
linux shell编程、bash编程、shell教程、bash教程、shell文档、bash文档、shell脚本、bash脚本【教程】第三章:特殊字符
文章目录
第四章. 变量和参数介绍
变量是脚本编程中的如何进行数据表现的办法. 它们可以在算术计算中作为操作数,在一个字符串表达式中作为符号表达抽象的意义或是其他的意义。变量是表示计算机内存中保存一种数据需要占的一个位置或一组的位置的标识。
4.1. 变量替换$
变量的名字是它的值保存的地方。引用它的值称为变量替换(variable substitution)。.
$
让我们仔细地区别变量和变量的值。如果variable1
是一个变量的名字,那么$variable1
就是引用这个变量的值――即这个变量它包含的数据。如果只有变量名出现(即指没有前缀$
),那就可能是在
1)声明一个变量或是在给这个变量赋值。
2)声明废弃这个变量,
3)导出(exported)变量,
4)或是在变量指示的是一种信号的特殊情况。(参考例子 29-5)。
变量赋值可以使用等于号(=),比如:var1=27。也可在read命令和在一个循环的情况下赋值,比如:for var2 in 1 2 3。
在一个双引号(" "
)里的变量引用不会禁止变量替换。所以双引号被称为部分引用,有时也称为"弱引用"。而在一个单引号里(' '
)的变量替换是被禁止的,变量名只被解释为普通的字面意思。所以单引号被称为"全局引用",有时也被称为强引用。从第五章可得到更多的细节讨论。.
注意$variable
实际上只是$variable
的简单的简写形式。在某些场合使用$variable
形式会引起错误,这时你可能需要使用$variable
的形式了。(参考下面的9.3节).
例子 4-1. 变量赋值与替换
#!/bin/bash
# Variables: 赋值和替换
a=375
hello=$a
#-------------------------------------------------------------------------
# =号的左右两边都不能有空白符.
# 如果有一个空白符会怎么样?
# 如果用 "VARIABLE =value",
# ^
#+ 脚本会以为"VARIABLE"是一个命令并且此命令带了一个参数"=value"。
# 如果用 "VARIABLE= value",
# ^
#+ 脚本会以为"value"是一个命令,
#+ 并且把环境变量"VARIABLE"赋为空值:""。
#-------------------------------------------------------------------------
echo hello # 没有引用变量,只是输出字符串 "hello".
echo $hello # 375
echo $hello # 这句和上面的一句一样
echo "$hello" # 375
echo "$hello" # 375
echo
hello="A B C D"
echo $hello # A B C D
echo "$hello" # A B C D
# 正如你所看到的:echo $hello和echo "$hello"产生不同的输出。
# ^ ^
# 把变量引起来会保留空白字符.
echo
echo '$hello' # $hello
# ^ ^
# 在单引号中的变量引用会被禁止,
#+ 字符"$"会仅仅被认为是一个普通的字符,而不是变量的前缀.
# 注意不同引用的不同效果.
hello= # Setting it to a null value.
echo "\\$hello (null value) = $hello" # $hello (null value) =[空格]
# 注意具有null值的变量不等同于废弃(unset)此变量
#+ 虽然最后的结果都是一样的(看下面的).
# --------------------------------------------------------------
# 在同一行里用空白字符隔开为多个变量赋值是可以的。
#
# 警告:这可能减少可读性,并且可能是不可移植的。
var1=21 var2=22 var3=$V3
echo
echo "var1=$var1 var2=$var2 var3=$var3"
# 在老版本的sh中这可能会引起问题
# --------------------------------------------------------------
echo; echo
numbers="one two three"
# ^ ^
other_numbers="1 2 3"
# ^ ^
# 如果给变量赋的值中有空白字符,引号是必须的。
#
echo "numbers = $numbers" # numbers = one two three
echo "other_numbers = $other_numbers" # other_numbers = 1 2 3
echo
echo "uninitialized_variable = $uninitialized_variable"
# 未初始化的变量具有null值 (即是没有值).
uninitialized_variable= # 声明,但没有初始化它 --
#+ 这就好像上面一样给它设置一个null 值
echo "uninitialized_variable = $uninitialized_variable"
# 它仍然是null值.
uninitialized_variable=23 # 赋值
unset uninitialized_variable # 销毁变量.
echo "uninitialized_variable = $uninitialized_variable"
# 结果仍然是null值.
echo
exit 0
一个未初始化的变量有一个”null”值――表示从没有被赋值过(注意null值不等于零)。在一个变量从未赋值之前就使用它通常会引起问题。
然而,仍然有可能在执行算术计算时使用一个未初始化的变量。
echo "$uninitialized" # (blank line)
let "uninitialized += 5" # Add 5 to it.
echo "$uninitialized" # 5
# 结论:
# 一个未初始化的变量没有值,
#+ 但是似乎它在算术计算中的值是零。
# 这个无法证实(也可能是不可移植)的行为。
参考例子 11-21.
4.2. 变量赋值=
=
赋值操作符(它的左右两边不能有空白符)
不要搞混了=
和-eq
,-eq
是比赋值操作更高级的测试。
注意:等于号(=
)根据环境的不同它可能是赋值操作符也可能是一个测试操作符。
例子 4-2. 简单的变量赋值(let变量赋值)(read从键盘读取输入值)
#!/bin/bash
# 裸变量
echo
# 什么时候变量是“裸”的?比如说,变量名前面没有$?
#当变量被赋值而不是引用时,我们称它为是裸变量。
# 赋值
a=879
echo "The value of \\"a\\" is $a."
# 用命令'let'赋值。
let a=16+5
echo "The value of \\"a\\" is now $a."
echo
# 在一个for循环里赋值(其实,这是一种伪赋值):
echo -n "Values of \\"a\\" in the loop are: "
for a in 7 8 9 11
do
echo -n "$a "
done
echo
echo
# 用'read'命令 (这也是一种赋值):
echo -n "Enter \\"a\\" "
read a
echo "The value of \\"a\\" is now $a."
echo
exit 0
例子 4-3. 简单且奇特的变量赋值
#!/bin/bash
a=23 # 简单的情况
echo $a # 23
b=$a
echo $b # 23
# 现在,来一点奇怪的赋值(命令替换)
a=`echo Hello!` # 把'echo'命令的结果赋值给变量'a'
echo $a # Hello!
# 注意在一个#+的命令替换结构中包含一个感叹号(!),
#+ 将不会工作。
#+ 因为感叹号触发了Bash"历史命令机制"
# 不过,在脚本里,历史命令机制是被禁用的.
a=`ls -l` # 把'ls -l'命令的结果赋给变量'a'
echo $a # 如果没有引号,则会删除多余tab键和空白符
echo
echo "$a" # 加了双引号,则能够原样保留空白符
# (参考"引用"章节)
exit 0
变量赋值也可以使用$(...)
机制(它是比斜引号更新的方法). 它实际是命令替换的一种形式.
# 摘自/etc/rc.d/rc.local
R=$(cat /etc/redhat-release)
arch=$(uname -m)
4.3. Bash变量是无类型的
不同于许多其他的编程语言,Bash不以"类型"来区分变量。本质上来说,Bash变量是字符串
,但是根据环境的不同,Bash允许变量有整数计算和比较。其中的决定因素是变量的值是不是只含有数字.
例子 4-4. 整数还是字符串?
#!/bin/bash
# int-or-string.sh: Integer or string?
a=2334 # 整数.
let "a += 1"
echo "a = $a " # a = 2335
echo # 仍然是整数.
b=$a/23/BB # 把变量a中的"23"替换为"BB"并赋给变量b
# 这使变量$b成为字符串
echo "b = $b" # b = BB35
declare -i b # 即使明确地声明它是整数也没有用
echo "b = $b" # b = BB35
let "b += 1" # BB35 + 1 =
echo "b = $b" # b = 1
echo
c=BB34
echo "c = $c" # c = BB34
d=$c/BB/23 # 把"BB"替换成"23"
# 这使变量$d成为一个整数
echo "d = $d" # d = 2334
let "d += 1" # 2334 + 1 =
echo "d = $d" # d = 2335
echo
# What about null variables?
e=""
echo "e = $e" # e =
let "e += 1" # 数值计算允许有null值操作?
echo "e = $e" # e = 1
echo # 空值(null)变量变成了整数
# 如果没有声明变量会怎么样?
echo "f = $f" # f =
let "f += 1" # 算术计算能通过吗?
echo "f = $f" # f = 1
echo # 没有预先声明的变量变为整数
# 在Bash中的变量确实是无类型的.
exit 0
变量没有类型既是幸运的也是悲惨的。它使脚本编程时有更多的弹性(但也可能把你弄晕)并能很容易地写出代码。但是,这也很容易不小心犯错误和养成坏的编程习惯。
程序员的负担就是要清楚地知道脚本中变量的类型。Bash不会帮你检查。
4.4. 特殊变量类型
局部变量
局部变量只在代码块或一个函数里有效 (参考函数里的局部变量)
环境变量(环境表)(export命令)
这种变量会影响Shell的行为和用户接口
在大多数情况下,每个进程都会有一个"环境表", 它由一组由进程使用的环境变量组成。这样看来,Shell看起来和其他的进程一样。
每次一个Shell启动时,它都会创建新的合适的环境变量。如果它增加或是更新一个环境变量,都会使这个Shell的环境表得到更新(译者注:换句话说,更改或增加的变量会立即生效),并且这个Shell所有的子进程(即它执行的命令)能继承它的环境变量。(译者注:准确地说,应该是后继生成的子进程才会继承Shell的新环境变量,已经运行的子进程并不会得到它的新环境变量)。
分配给环境变量的总空间是有限的,如果创建太多的环境变量或有些环境变量的值太长而占用太多空间会出错。
bash$ eval "`seq 10000 | sed -e 's/.*/export var&=ZZZZZZZZZZZZZZ/'`"
bash$ du
bash: /usr/bin/du: Argument list too long
(多谢Stéphane Chazelas的澄清和提供了上面的例子)
如果一个脚本要设置一个环境变量,则需要将它导出(”exported”),也就是说要通知到脚本的环境表。这就是export命令的功能。
一个脚本只能导出(export)变量到子进程,也就是说只能导出到由此脚本生成的命令或进程中。在一个命令行中运行的脚本不能导出一个变量影响到命令行的环境。子进程不能导出变量到生成它的父进程中。
位置参数$0, $1, $2, $3 . . .
命令行传递给脚本的参数是: $0, $1, $2, $3 . . .
$0
是脚本的名字,$1
是第一个参数,$2
是第二个参数,$3
是第三个,以此类推。[1] After $9
, 在位置参数$9
之后的参数必须用括号括起来,例如:$10, $11, $12
.
特殊变量$*
和$@
表示所有的位置参数。
例子 4-5. 位置参数(脚本启动时的参数)$0~$num
、$*
和$@
表示所有的位置参数、$#
参数个数、echo $!#
获取最后一个参数的值,可以通过变量$0
判断脚本被执行的路径,这个还是有用的;位置参数后加额外字符防止空值(NULL值)报错
#!/bin/bash
# 至少以10个参数运行这个脚本,例如:
# ./scriptname.sh a b c d e f g h i j
MINPARAMS=10
echo
echo "The name of this script is \\"$0\\"." # The name of this script is "./scriptname.sh".
# 用./表示当前目录
echo "The name of this script is \\"`basename $0`\\"." # The name of this script is "scriptname.sh".
# 去掉路径名(查看'basename'命令)
echo
if [ -n "$1" ] # 被测试的变量被双引号引起(-n 判断非空)
then
echo "Parameter #1 is $1" # 使用引号来使#被转义 # Parameter #1 is a
fi
if [ -n "$2" ]
then
echo "Parameter #2 is $2" # Parameter #2 is b
fi
if [ -n "$3" ]
then
echo "Parameter #3 is $3" # Parameter #2 is c
fi
# ...
if [ -n "$10" ] # 大于 $9的参数必须用花括号括起来.
then
echo "Parameter #10 is $10" # Parameter #10 is j
fi
echo "-----------------------------------"
echo "All the command-line parameters are: "$*"" # All the command-line parameters are: a b c d e f g h i j
echo
echo "$#" # 10
if [ $# -lt "$MINPARAMS" ] # -lt 小于
then
echo
echo "This script needs at least $MINPARAMS command-line arguments!"
fi
echo
echo "$#" # 10
echo "$"$#"" # $10
echo $"$#" # 10
echo $$# # 30783
echo $"$#" # ./scriptname.sh: 行 31: $"$#": 错误的替换
echo $`$#` # ./scriptname.sh: 行 32: $`$#`: 错误的替换
echo $$($#) # ./scriptname.sh: 行 33: $$($#): 错误的替换
echo
last=$#
echo last # last
echo $last # 10
echo $last # 10
echo $10 # j
echo $!last # j
echo $!# # j
exho $!$# # ./scriptname.sh: 行 44: $!$#: 错误的替换
exit 0
将花括号 用于位置参数会导致引用传递给命令行脚本的最后一个参数方法变得相当简单。 这也需要间接引用。
args=$# # 传给脚本的参数个数.
lastarg=$!args
# 也可以用: lastarg=$!#
# (多谢, Chris Monson.)
# 注意lastarg=$!$#是不会工作的.
由不同的执行名字来调用脚本,一些脚本能够以不同的操作来执行。如果要能办到这一点,脚本需要检查变量$0
来确定脚本是如何被调用的。也有可能存在符号链接的路径来调用脚本的情况。参考例子 12-2.(ar:可以通过变量$0
判断脚本被执行的路径,这个还是有用的)
如果一个脚本需要提供一个命令行参数来执行,但是这个参数没有提供,这可能引起一个空值(null值)被赋给一个脚本中使用的变量,从而使脚本产生非预期的效果. One way to prevent this is to append an extra character to both sides of the assignment statement using the expected positional parameter.(防止这种情况的一种方法是使用预期的位置参数在赋值语句的两侧附加一个额外的字符
。)
variable1_=$1_ # Rather than variable1=$1
# This will prevent an error, even if positional parameter is absent.(即使位置参数不存在,这可以防止错误。)
critical_argument01=$variable1_
# The extra character can be stripped off later, like so.(额外的字符可以在以后被剥离,就像这样。)
variable1=$variable1_/_/
# Side effects only if $variable1_ begins with an underscore.(仅当 $variable1_ 以下划线开头时才有副作用。)
# This uses one of the parameter substitution templates discussed later.(这使用稍后讨论的参数替换模板之一。)
# (Leaving out the replacement pattern results in a deletion.)(省略替换模式会导致删除。)
# A more straightforward way of dealing with this is
#+ to simply test whether expected positional parameters have been passed.(一种更直接的处理方法是简单地测试预期的位置参数是否已通过。)
if [ -z $1 ] # 判断是否为空字符串
then
exit $E_MISSING_POS_PARAM
fi
# However, as Fabian Kreutz points out,
#+ the above method may have unexpected side-effects.
# A better method is parameter substitution:
# $1:-$DefaultVal
# See the "Parameter Substition" section
#+ in the "Variables Revisited" chapter.
# 然而,正如 Fabian Kreutz 指出的那样,上述方法可能会产生意想不到的副作用。 更好的方法是参数替换: $1:-$DefaultVal 。 请参阅“重新访问的变量”一章中的“参数替换”部分。
例子 4-6. wh,whois 查询服务器信息(看不懂。。。)
#!/bin/bash
# ex18.sh
# Does a 'whois domain-name' lookup on any of 3 alternate servers:
# ripe.net, cw.net, radb.net
# 在 3 个备用服务器中的任何一个上进行“whois 域名”查找:成熟.net、cw.net、radb.net
# Place this script -- renamed 'wh' -- in /usr/local/bin
# Requires symbolic links:
# ln -s /usr/local/bin/wh /usr/local/bin/wh-ripe
# ln -s /usr/local/bin/wh /usr/local/bin/wh-cw
# ln -s /usr/local/bin/wh /usr/local/bin/wh-radb
E_NOARGS=65
if [ -z "$1" ] # 如果第一个参数不等于空
then
echo "Usage: `basename $0` [domain-name]"
exit $E_NOARGS
fi
# Check script name and call proper server.(检查脚本名称并调用适当的服务器。)
case `basename $0` in # Or: case $0##*/ in
"wh" ) whois $1@whois.ripe.net;;
"wh-ripe") whois $1@whois.ripe.net;;
"wh-radb") whois $1@whois.radb.net;;
"wh-cw" ) whois $1@whois.cw.net;;
* ) echo "Usage: `basename $0` [domain-name]";; # ar:啥意思啊,看不懂。。。
esac
exit $? # 命令或程序执行完后的状态,返回0表示执行成功
shift命令使位置参数都左移一位。
$1 <--- $2, $2 <--- $3, $3 <--- $4
, 以此类推.
原来旧的$1
值会消失,但是$0
(脚本名称)不会改变. 如果你把大量的位置参数传给脚本,那么可以使用shift命令存取超过10的位置参数, 虽然这个功能也能由bracket
花括号 做到.
例子 4-7. 使用 shift 存取参数(shift命令使位置参数都左移一位)
#!/bin/bash
# 用 'shift'命令逐步存取所有的位置参数
# 给这个脚本一个命名,比如说shft,
#+ 然后以一些参数来调用这个脚本,例如
# ./shft a b c def 23 skidoo
until [ -z "$1" ] # 直到所有的位置参数被存取完...
do
echo -n "$1 "
shift
done
echo # 换行.
exit 0
示例:
同样,shift命令也可以在需要传递一些参数的函数上以类似的方式工作.参考例子 33-15.
注:
[1]
$0
参数由调用脚本的进程设置。依照习惯,这个参数是脚本的名字。详细的细节可以查看C函数execv
的手册页。
指令笔记
unset uninitialized_variable # 销毁变量.
以上是关于:变量和参数介绍的主要内容,如果未能解决你的问题,请参考以下文章