2 Shell编程
2.1 Shell变量
-
变量用来存放各种数据。脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则。
-
在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。
-
这意味着,Bash shell 在默认情况下不会区分变量类型,即使你将整数和小数赋值给变量,它们也会被视为字符串,这一点和大部分的编程语言不同。例如在C语言或者 C++中,变量分为整数、小数、字符串、布尔等多种类型。
-
当然也可以使用 Shell declare关键字显式定义变量的类型,但在一般情况下没有这个需求,Shell 开发者在编写代码时自行注意值的类型即可。
-
定义变量:Shell 支持以下三种定义变量的方式:
variable=value
variable='value'
variable="value"
- variable 是变量名,value 是赋给变量的值。如果 value 不包含任何空白符(例如空格、Tab 缩进等),那么可以不使用引号;如果 value 包含了空白符,那么就必须使用引号包围起来。使用单引号和使用双引号也是有区别的
注意,赋值号
=
的周围不能有空格,这和大部分编程语言都不一样。
-
Shell 变量的命名规范和大部分编程语言都一样:
- 变量名由数字、字母、下划线组成;
- 必须以字母或者下划线开头;
- 不能使用 Shell 里的关键字(通过 help 命令可以查看保留关键字)。
-
使用一个定义过的变量,只要在变量名前面加美元符号
$
即可,如:
str="zk"
echo $str zk
echo {$str} {zk}
echo ${str} zk
- 变量名外面的花括号
{ }
是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
name="zs"
echo "hello ${name}too"
-
如果不给 skill 变量加花括号,写成
echo "hello $nametoo"
,解释器就会把 $nametoo当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。推荐给所有变量加上花括号{ }
,这是个良好的编程习惯。 -
修改变量的值:已定义的变量,可以被重新赋值,如:
name="zs"
echo "hello ${name}too"
name="ls"
echo "hello ${name}too"
第二次对变量赋值时不能在变量名前加
$
,只有在使用变量时才能加$
- 单引号和双引号的区别
#!/bin/bash
name="zs"
form1='hello ${name}'
form2="hello ${name}"
echo $form1 # hello ${name}
echo $form2 # hello zs
-
以单引号
' '
包围变量的值时,单引号里面是什么就输出什么,即使内容中有变量和命令(命令需要反引起来)也会把它们原样输出。这种方式比较适合定义显示纯字符串的情况,即不希望解析变量、命令等的场景。 -
以双引号
" "
包围变量的值时,输出时会先解析里面的变量和命令,而不是把双引号中的变量名和命令原样输出。这种方式比较适合字符串中附带有变量和命令并且想将其解析后再输出的变量定义。 -
所以,如果变量的内容是数字,那么可以不加引号;如果真的需要原样输出就加单引号;其他没有特别要求的字符串等最好都加上双引号,定义变量时加双引号是最常见的使用场景。
-
将命令的结果赋值给变量:Shell 也支持将命令的执行结果赋值给变量,常见的有以下两种方式:
variable=`command`
variable=$(command)
-
第一种方式把命令用反引号
$()
包围起来,区分更加明显,所以推荐使用这种方式。
-
删除变量:使用 unset 命令可以删除变量。语法:
unset variable_name
2.2 Shell命令替换
-
Shell 命令替换是指将命令的输出结果赋值给某个变量。比如,在某个目录中输入 ls 命令可查看当前目录中所有的文件,但如何将输出内容存入某个变量中呢?这就需要使用命令替换了,这也是 Shell 编程中使用非常频繁的功能。
-
Shell 中有两种方式可以完成命令替换,一种是反引号
$()
,使用方法如下:
variable=`commands`
variable=$(commands)
-
其中,variable 是变量名,commands 是要执行的命令。commands 可以只有一个命令,也可以有多个命令,多个命令之间以分号
;
分隔。 -
如,date 命令用来获得当前的系统时间,使用命令替换可以将它的结果赋值给一个变量。
#!/bin/bash
start_time=`date` #开始时间,使用``替换
sleep 5s #休眠5秒
end_time=$(date) #结束时间,使用$()替换
echo "Begin time: $start_time"
echo "Finish time: $end_time"
- 运行脚本,5 秒后可以看到输出结果:
- 使用 data 命令的
%s
格式控制符可以得到当前的 UNIX 时间戳,这样就可以直接计算脚本的运行时间了。UNIX 时间戳是指从 1970 年 1 月 1 日 00:00:00 到目前为止的秒数
#!/bin/bash
start_time=`date +%s` #开始时间,使用``替换
sleep 5s #休眠5秒
end_time=$(date +%s) #结束时间,使用$()替换
getTime=$start_time-$end_time
getTime2=$((start_time-end_time)) #时间差
echo "Begin time: $start_time"
echo "Finish time: $end_time"
echo "Get time: $getTime"
echo "Get time2: $getTime2"
- 第 6 行代码中的
(( ))
是 Shell 数学计算命令。和 java等编程语言不同,在 Shell 中进行数据计算不那么方便,必须使用专门的数学计算命令,(( ))
就是其中之一
注意,如果被替换的命令的输出内容包括多行(也即有换行符),或者含有多个连续的空白符,那么在输出变量时应该将变量用双引号包围,否则系统会使用默认的空白符来填充,这会导致换行无效,以及连续的空白符被压缩成一个。
-
很明显输出不加双引号的变量时,文本内容出现混乱。所以,为了防止出现格式混乱的情况,我建议在输出变量时加上双引号。
-
反引号和 $():原则上讲,上面提到的两种变量替换的形式是等价的,可以随意使用;但是,反引号毕竟看起来像单引号,有时候会对查看代码造成困扰,而使用 $() 就相对清晰,能有效避免这种混乱。而且有些情况必须使用
(
)
:
():
():() 支持嵌套,反引号不行。
[c.biancheng.net]$ Fir_File_Lines=$(wc -l $(ls | sed -n '1p'))
[c.biancheng.net]$ echo "$Fir_File_Lines"
36 anaconda-ks.cfg
要注意的是,$() 仅在 Bash Shell 中有效,而反引号可在多种 Shell 中使用。所以这两种命令替换的方式各有特点
2.3 Shell位置参数
-
位置参数:运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用
$n
的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。 -
在调用函数时也可以传递参数。Shell 函数参数的传递和其它编程语言不同,没有所谓的形参和实参,在定义函数时也不用指明参数的名字和数目。换句话说,定义 Shell 函数时不能带参数,但是在调用函数时却可以传递参数,这些传递进来的参数,在函数内部就也使用
$n
的形式接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。 -
这种通过
$n
的形式来接收的参数,在 Shell 中称为位置参数。 -
在变量的命名时变量的名字必须以字母或者下划线开头,不能以数字开头;但是位置参数却偏偏是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”。
-
除了 $n,Shell 中还有 KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 1: #̲、*、
@
、
@、
@、?、$$ 几个特殊参数
-
给脚本文件传递位置参数并运行 test.sh,并附带参数:
其中zs是第一个位置参数,20是第二个位置参数,两者之间以空格分隔。
#!/bin/bash
echo "name: $1"
echo "age: $2"
- 给函数传递位置参数:
#!/bin/bash
#定义函数
function funs{
echo "name: $1"
echo "age: $2"
}
#调用函数
funs zk 20
如果参数个数太多,达到或者超过了 10 个,那么就得用
${n}
的形式来接收了,例如8
、
{8}、
8、{10}。
{ }
的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }
是一样的效果。在 Shell 中,传递位置参数时除了能单独取得某个具体的参数,还能取得所有参数的列表,以及参数的个数等信息
- 存在问题:运行脚本:syntax error near unexpected token `$‘{\r’
原因:脚本是在Windows下写的,Windows和Linux的换行符号不同,所以在Linux中执行脚本的时候报错。
查看:使用notepad++打开脚本,视图→ 显示符号→ 显示所有字符,如图所示,换行符是 CRLF,但是Linux的是LF。
2.4 Shell特殊变量
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名。 |
$n(n≥1) | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。当被双引号" " 包含时,$@ 与 $* 稍有不同, |
$? | 上个命令的退出状态,或函数的返回值, |
$$ | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。 |
- 给脚本文件传递参数:编写下面的代码,并保存为 test.sh:
#!/bin/bash
echo "ProcessID: $$"
echo "FileName: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
#!/bin/bash
#定义函数
function func(){
echo "ProcessID: $$"
echo "FileName: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
}
#调用函数
func zk 20
2.5 Shell $?
-
$? 是一个特殊变量,用来获取上一个命令的退出状态,或者上一个函数的返回值。
-
退出状态:就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1,这和C语言的 main() 函数是类似的。也有一些命令返回其他值,表示不同类型的错误
-
$? 获取上一个命令的退出状态.编写下面的代码,并保存为 test.sh:
问题:syntax error near unexpected token `then’
原因:if 与‘[‘之间没有加空格导致的。 ‘==’两边必须也得加空格,否则会一直判true。
#!/bin/bash
#定义函数
if [ "$1" == 0 ]
then
exit 0 #参数正确,退出状态为0
else
exit 1 #参数错误,退出状态1
fi
exit
表示退出当前 Shell 进程,我们必须在新进程中运行 test.sh,否则当前 Shell 会话(终端窗口)会被关闭,我们就无法取得它的退出状态了。
#!/bin/bash
#定义两数相乘函数
function fun(){
return $(expr $1 + $2)
}
fun 20 30 #调用函数
echo $? #获取函数返回值
请注意:Shell 函数中的 return 关键字用来表示函数的退出状态,而不是函数的返回值;Shell 不像其它编程语言,没有专门处理返回值的关键字。
以上处理方案在其它编程语言中没有任何问题,但是在 Shell 中是非常错误的,Shell 函数的返回值和其它编程语言大有不同
参考文献:
Shell变量:Shell变量的定义、赋值和删除
下一篇:Shell学习-04-字符串操作
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123690.html