命令行之巅:Linux Shell编程的至高艺术(上)
文章一览
- 前言
- 一、shell概述
- 1.1 shell的特点和类型
- 1.1.1 **shell的特点:**
- 1.1.2 常用shell类型
- 1.2 shell脚本的建立和执行
- 1.2.1 建立shell脚本
- 1.2.2 执行shell脚本的方式
- 1.2.3 shell程序实例
- 二、shell变量与算数运算
- 2.1 简单shell变量
- 2.1.1 简单变量定义和赋值
- 2.1.2 引用变量值
- 2.1.3 删除变量
- 2.2 数组
- 2.3 位置参数
- 2.3.1 位置参数
- 2.3.2 shift命令
- 2.3.3 用set命令为位置参数赋值
- 2.4 预先定义的特殊变量
- 2.5 环境变量
- 2.6 运算
- 2.6.1 let命令
- 2.6.2 运算符及其优先级和结合性
- 2.6.3 关系运算符
- 2.6.4 算数运算符
- 2.6.5 布尔运算符
- 2.6.6 逻辑运算符
- 2.6.7 字符串运算符
- 获取字符串长度
- 2.6.8 文件测试运算符
前言
在浩瀚的数字世界中,Linux以其坚不可摧的内核和无限的可能性,成为了开发者和系统管理员的挚爱。而在这个由代码编织的宇宙里,Shell程序就像是一把钥匙,能够解锁Linux操作系统的无尽潜能。今天,我们将一同探索Linux中的shell程序设计,这是一段既充满挑战又令人兴奋的旅程。
Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。
实际上Shell是一个命令解释器, 它解释由用户输入的命令并且把它们送到内核。不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序。 Shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果。
本篇文章将介绍什么是shell以及shell的中的变量运算。
一、shell概述
1.1 shell的特点和类型
1.1.1 shell的特点:
- 组合新命令很简单;
- 提供了文件名扩展字符;
- 可以直接使用shell的内置命令 ;
- 允许灵活地使用数据流 ;
- 结构化的程序模块 ;
- 提供了在后台(&)执行命令 ;
- 提供了可配置的环境;
- 提供了一个高级的命令语言 。
1.1.2 常用shell类型
- Bourne shell(简称sh)
- C—shell(简称csh)
- Korn shell(简称ksh)
- Bourne Again shell(简称bash)
1.2 shell脚本的建立和执行
1.2.1 建立shell脚本
建立shell脚本的步骤同建立普通文本文件的方式相同,如:
vi ex1
1.2.2 执行shell脚本的方式
执行shell脚本的常用方式基本上有两种:
(1)以脚本名作为参数。其一般形式是:
$ bash 脚本名 [参数]
$ · 脚本名 [参数]
(2)将shell脚本的权限设置为可执行,然后在提示符下直接执行它。
$ chmod a+x ex2
$ PATH=$PATH:•
$ ex2 或者 $ •/ex2
1.2.3 shell程序实例
注意,一定要写成 ./test.sh
,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin
等在 PATH 里,我们的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要使用 ./test.sh 告诉系统在当前目录寻找。
二、shell变量与算数运算
2.1 简单shell变量
2.1.1 简单变量定义和赋值
变量名=字符串
注意:在赋值号“=”的两边没有空格 , 例如:
myfile=/home/cieeqc/ff/m1.c
变量名以字母或下线符打头的字母、数字和下线符序列,大小写字母意义不同。
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
2.1.2 引用变量值
- 在程序中引用变量值时,要在变量名前面加上一个“$”符号。
$ dir=/home/ciee/ff
$ echo $dir
/home/ciee/ff (显示变量dir的值)
$ echo dir
dir (显示一般的字符串常量dir)
$ echo $Dir
(显示一个空串)
$
- 如果在赋给变量的值中含有空格、制表符或换行符,那么,就应该用双引号把这个字符串括起来。
应注意的情况:
-
$ dir=/home/ci $ cat ${dir}ee/file1.c #将把文件/home/ciee/m1.c显示出来 3 而 $ cat $dirqc/file1.c #系统会给出错误信息
-
$ dir1=/home/ciee/ff/prog $ ls $dir1 $ cat $dir1/exam.c
- 变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done
如果不给skill变量加花括号,写成echo “I am good at $skillScript”,解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
2.1.3 删除变量
使用 unset 命令可以删除变量。语法:
使用 unset 命令可以删除变量。语法:
变量被删除后不能再次使用。unset 命令不能删除只读变量
#!/bin/sh
myUrl="http://www.ipieuvre.com"
unset myUrl
echo $myUrl
以上实例执行后将没有任何输出。
2.2 数组
Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小(与 PHP 类似)。
与大部分编程语言类似,数组元素的下标由0开始。
- 对数组元素赋值的一般形式是:
数组名[下标]=值
$ city[0]=Beijing
$ city[1]=Shanghai
$ city[2]=Tianjin
-
用declare命令显式声明一个数组,一般形式是:
declare -a
-
数组名读取数组元素值的一般格式是:
${数组名[下标]}
例如:$ echo ${city[0]}
-
数组初始化的一般形式是:
数组名=(值1 值2 … 值n) $ A=(this is an example of shell script)
$ A=(this is an example of shell script)
$ echo ${A[0]} ${A[2]} ${A[3]} ${A[6]}
this an example script
$ echo ${A[8]}
(A[8]超出了数组A的范围,所以它的值是空串。)
$ ▌
使用*或@作为下标,则表示数组中所有元素。
2.3 位置参数
2.3.1 位置参数
exam m1 m2 m3 m4
$0 $1 $2 $3 $4 $5 $6 $7 $8 $6 ${10} ${11}
这种变量不能用赋值语句直接赋值,只能通过命令行上对应位置的实参传值。
$0始终表示命令名或shell脚本名。
2.3.2 shift命令
用shift命令移动位置参数
$0
:脚本的名称。$1
到$9
:传递给脚本的第一个到第九个参数。$#
:传递给脚本的参数总数。$*
和$@
:所有的位置参数,区别在于,$*
会将所有参数视为一个整体,而$@
会将每个参数视为独立的元素,这在循环遍历参数时非常有用。
示例:
假设你有一个名为 script.sh
的脚本,并且你通过以下命令调用它:
shell
./script.sh arg1 arg2 arg3
在这个例子中,arg1
、arg2
和 arg3
是传递给脚本的位置参数。在脚本内部,你可以这样访问它们:
$1
的值是arg1
。$2
的值是arg2
。$3
的值是arg3
。$#
的值是3
,因为有3个参数。$*
的值是arg1 arg2 arg3
,所有参数作为一个整体。$@
的值是arg1 arg2 arg3
,每个参数作为独立的元素。
以下是如何在脚本中使用这些位置参数的一个简单示例:
#!/bin/bash
# 打印脚本名称
echo "Script name: $0"
# 循环遍历所有参数
echo "Looping through all arguments:"
for arg in "$@"; do
echo "Argument: $arg"
done
# 打印参数总数
echo "Total number of arguments: $#"
# 打印所有参数作为一个整体
echo "All arguments as a whole: $*"
2.3.3 用set命令为位置参数赋值
$ cat exam4
#!/bin/bash
# exam4: shell script to combine files and count lines
# using command set to set positional parameters
set file1.c file2.c
cat $1 $2 $3 | wc -l
# end
$ exam4
????
$ ▌
2.4 预先定义的特殊变量
⑴$#——除脚本名外,命令行上参数的个数。
⑵$?——上一条前台命令执行后的返回值(也称“退出码”等)。 0表示没有错误,其他任何值表示有错误。
⑶$$——当前进程的进程号(ID号)。
⑷$!——上一个后台命令对应的进程号。
⑸$*——表示在命令行上实际给出的所有实参。如输入下面的命令行:
exam3 A B C D E F G H I J K
# 则$* 就是:A B C D E F G H I J K
#而“$*”就等价于:
#"$1 $2 $3……",即:" A B C D E F G H I J K"。
⑹$@——它与$基本功能相同。但“$@”与“$”不同。
“$@”就等价于: “$1” “$2”……,在上面情况下,就是"A" “B” “C”……“K”。
(7) $- 显示shell的当前选项,与set
命令功能相同
2.5 环境变量
(1)HOME:用户主目录的全路径名。如/home/myname
(2)LOGNAME:即用户注册名
(3)PWD:当前工作目录的路径。
(4)PATH:shell查找命令的路径(目录)列表,各个目录用冒号(:)隔开。
#用户可以设置它:
$ PATH=$PATH:$PWD
(5)PS1:shell的主提示符。 \$ PS1="$LOGNAME> "
(6)SHELL:当前使用的shell。通常,它的值是/bin/bash。
-
可以用env命令列出当前环境下的所有环境变量及其值,也可用echo命令察看任何一个环境变量的值。
-
当更改了环境变量的值以后,往往利用export命令将这些变量输出,使它们成为公用量。例如:
$ export HOME PATH PS1
2.6 运算
2.6.1 let命令
bash中执行整数算术运算的命令是let,其语法格式为: let arg …
其中,arg是单独的使用C语言语法的算术表达式。如 let "j=i6+2" let 命令的替代表示形式是: ((算术表达式)) 如 ((j=i6+2))
2.6.2 运算符及其优先级和结合性
其运算符及其优先级和结合性基本上与C语言的相同。
当表达式中有shell的特殊字符时,必须用双引号将其括起来。例如,let “val=a|b”
。只有使用**$((算术表达式))**形式才能返回表达式的值,例如 :
$ echo "((12*9))"
((12*9))
$ echo "$((12*9))"
108
2.6.3 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
2.6.4 算数运算符
注意:条件表达式要放在方括号之间,并且要有空格,例如: [ a = = a== a==b] 是错误的,必须写成 [ $a == $b ]。
2.6.5 布尔运算符
2.6.6 逻辑运算符
2.6.7 字符串运算符
获取字符串长度
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
2.6.8 文件测试运算符
文件测试运算符用于检测 Unix 文件的各种属性。
其他检查符:
-S: 判断某文件是否 socket。
-L: 检测文件是否存在并且是一个符号链接。
eg:变量 file 表示文件shellf.sh,它的大小为 100 字节,具有 rwx 权限。