Shell编程基础整理 -- 变量
前言后语
- 所需基础:
+ 基础的终端文件操作指令
- 学习目标:
+ 使用终端编写shell脚本,了解PATH
- 预期结果:
能够通过脚本来执行命令行指令(例如启动postgresql)
脚本可以作为shell指令执行
使用其他语言可以调用该脚本并且给出可读/可用的返回值
待定。。。
铺垫知识
待更新
环境准备
我使用的是Linux Mint 21.3 Cinnamon,内核版本5.15.0
打开终端即可
或者写一个.sh文件 在文件第一行指定解释器(例如bash解释器对应的就是 #!/bin/sh)
下面写脚本内容
然后给这个文件执行权限
执行即可
基础知识
一切的基础:变量
基本内容:变量定义与调用
参考网站
https://www.runoob.com/linux/linux-shell-variable.html
https://zhuanlan.zhihu.com/p/418357041
pre.
- 可用变量类型:整数、字符串、数组
然而,实质上在bash shell中,我们的值全部以字符串的形式存储,只是不同“类型”可使用的操作不同。 - shell支持在命令行界面进行编程,在终端创建的变量在当前终端始终可用
(也就是说对于某些情况 你不一定需要反复定义某个变量 只要直接调用之前创建好的即可)
使用方法
-
变量定义:
-
字符串串:
var_name=“strings”/var_name=‘strings’/var_name=strings* 字符串内的特殊符号要使用转义符号\ e.g:\" * 双引号定义的字符串在内部允许变量替换 * 无引号定义方式与双引号一样自由和奔放,但是出现空格会导致后面的字符被解释器认作参数 * 单引号定义的字符串为常量字符串,若字符串内有变量符号,会作为正常字符输出 * 单引号定义的字符串内部若需出现单引号 需要成对出现 此时表示拼接子串内容示例
a="lalala" && b="${a}hahaha" && echo $b的输出会是lalalahahaha
a="lalala" && b=${a}hahaha && echo $b的输出会是lalalahahaha
a="lalala" && b=${a} hahaha && echo $b的输出会报错,因为hahaha被认为是命令了
b='lalala '123456' hahaha' && echo $b的输出会是lalala 123456 hahaha
a="lalala" && b='${a}hahaha' && echo $b的输出会是${a}hahaha
b='lalala '123456' hahaha' && echo $b的输出会是lalala 123456 hahaha
-
带值变量:
var_name=value/declare -i var_name=var_name* 前者不限定变量类型,只是赋值为整数 * 后者显式声明该变量为整型,解释器会尝试将赋值转换为整数 -
常量约俗:
CONST_NAME = something
-
-
调用通则:
- 基本方法:
$name该方法调用了一个变量,其中name为变量名
- 标识边界:
${name}该方法调用了一个变量,并且显式的标注了变量名为name
- 使用示例:
"unrelevent strings${name}unrelevent strings "该方法调用了一个name变量,其中显式的标注了变量名为name,前后的字符串不会被认作变量名
- 只读标注:
readonly existed_var之后更改该变量会报错readonly
- 删除变量:
unset existed_var之后调用该变量不会产生结果
- 基本方法:
-
注意事项:
- 变量定义 等号两侧不能含有空格
× 例如( var_name = something )× - 变量名不能使用空格和特殊符号(不包括下划线 _ )
- 不要使用保留关键字(例如 if)
- 变量定义 等号两侧不能含有空格
进阶内容:变量的操作和组合
-
数组
- 定义方式
与大多数编程语言类似,shell也支持数组,但他仅支持一维数组
定义方式:
数组各个元素间使用空格或者换行符分隔:array_name=(value0 value1 value2 value3)array_name=( value0 value1 value2 value3 )
- 调用方式:
与大多数语言类似,使用方括号即可(因为早期计算机编程语言中多使用方括号来表示“地址偏移” 尽管这里只是形式上追随一致)
${name[index]}
- 获取长度:
- 获取数组元素个数:
${#name[@]}或者${#name[*]} - 获取数组当前元素的长度:
${#name[index]}(就像正常调用一个变量一样)
- 获取数组元素个数:
- 定义方式
-
字符串
- 长度获取:在所取变量的变量名前加入#(需要使用显式边界标识)
例如: 先执行 strings="strings" 然后执行 echo ${#strings} ,输出为7为什么需要显式指定边界?
如果没有使用显式边界标识:
先执行 strings="strings" 然后执行 echo $#strings ,输出为0strings问题分析:
先执行 strings="strings" 然后执行 echo $strings ,输出为strings 执行 echo $#s ,输出为0s 执行 echo $s ,输出为s 执行 echo $# ,输出为0说明这个问题是由于不显式指定边界,#指令读取到的变量为一个空字符串,然后其后的内容被作为额外的字符串送到了输出
- 获取字串:变量名后加入
:a:b(需要使用显式边界标识)
其中 a 为字串起始位置(第a个字符后开始读取),而 b 为字串截断大小(一共取b个字符)
其中 a 必须存在,b可以省略,表示从第a个字符后一直到末尾
例如: 先执行strings="strings" 然后执行 echo ${strings:3} ,输出为ings 先执行strings="strings" 然后执行 echo ${strings:3:1} ,输出为i与获取大小不同,如果不指定边界范围,解释器会直接将整行认作字符串送到输出
- 查找位置:使用expr命令在指定字符串中查找对应字符第一次出现的位置
注意使用expr的时候字符串最好带有双引号(原因见后文)
`expr index "STRINGS" CHAR(s)`注意使用的是反引号
在指定字符串中查找给定字符第一次出现的位置,如果有多个字符多个位置,则以第一次出现的那个字符的那个位置为准例如: 先执行strings="strings" 然后执行 echo `expr index "$strings" r` , 输出3 echo `expr index "$strings" gr`, 输出3 echo `expr index "$strings" gn`, 输出5 echo `expr index "$strings" gs`, 输出1实际上,expr是shell引进的外部的数学计算工具,我们之后还会接触到他
为什么传入参数的字符串上需要使用双引号?
在给定的范例中可能看不出来,让我们定义一个新的字符串:Who_I_Am="I am Jerry"这是一个带有空格的字符串,我们搜索字母m
echo ${Who_I_Am} (输出I am Jerry) echo ${#Who_I_Am} (输出10) echo `expr index ${Who_I_Am} m` (报错!)expr: 语法错误:未预期的参数 "Jerry"
我们的解释器抛出了一个错误,从报错上分析,他将参数Jerry输入进了expr,
我们的确需要他读取“Jerry”,但是注意我们给定的字符串,应该为"I am Jerry",而非“Jerry”
很明显expr读取到字符串后,字符串被从中截断,导致“Jerry”被单独列出来,产生了多余的参数输入
在和字符串相关的操作中,很经典的一类问题是,字符串内的“关键词”和“特殊符号”被读取为操作,导致输出与预期结果不符。
尝试输入以下指令:echo `expr index I am Jerry m`,发现报错信息一致也就是说,解释器先进行了变量替换,导致echo后面执行的实际命令为expr index I am Jerry m,我们的"I am Jerry"由于含有空格,在执行expr操作的时候被拆成了字符串I 字符序列am 和多余的参数Jerry和m!
由于expr只接受两个输入参数,尝试输入Jerry的时候解释器发现问题,则报错解决办法很简单,我们告诉expr,我们那个变量是一整条字符串,那么就不会产生这个“错位问题”
即在expr的字符串参数处外括双引号(还记得我们说过 双引号字符串允许变量替换这件事吗)
也就是:echo `expr index "${Who_I_Am}" m`成功执行,结果为4
这类问题其实是非常经典的“输入类型判断错误”问题
有一些相关的非常有意思的应用,比如“SQL注入”,感兴趣可以了解一下:数据库的SQL语言中,假设我们有一个登陆界面,需要验证用户输入的用户名和密码的匹配问题: SELECT * FROM users WHERE username = '[用户输入内容]' AND password = '[用户输入内容] 如果有人在username处输入: admin'-- SELECT * FROM users WHERE username = 'admin' --' AND password = '[用户输入]' --是sql中的注释符号,这会导致实际传入的语句变为: SELECT * FROM users WHERE username = 'admin' 于是我们的用户就跳过密码检查,成为了系统的管理员 由于没有进行严格的类型检查,输入的字符串被错误的当成了操作命令,给了攻击者可乘之机

浙公网安备 33010602011771号