Shell 脚本

其他连接:
shell中各种括号的作用'()''{}''[]'

Shell 环境

他扩展名一般为sh, 不起作用就是为了见名知意。

shell脚本的执行方法一定为./test.sh, 不能少了./, 少了就是去PATH(/bin, /sbin, /usr/bin,/usr/sbin)寻找了。

一般shell脚本需要在第一行确定解释器,比如#!/bin/bash, Linux 的 Shell 种类众多,常见的有:

bash 复制代码
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
...... 

Bash 也是大多数Linux 系统默认的 Shell。

1. Shell 变量

正确定义变量,下面举几个例子,判断正误:

bash 复制代码
your_name = "runoob" (x)变量名和等号之间不能有空格。
0your_name="runoob" (x)不能以数字开头
then="runoob" (x)不能用shell关键字
?your_n&ame="runoob" (x)不能用特殊符号
pi=3.1415926 (x)常量要大写,小写不推荐
your name="runoob" (x)不能有空格
your_name="runoob" (√)
RUNOOB="www.runoob.com"(√)
LD_LIBRARY_PATH="/bin/"(√)
_var="123"(√)
var2="abc"(√)

我蹦出来一个问题:看上面都在用双引号,单引号可以吗?
shell中定义字符串变量(shell默认变量为字符串)用双引号和单引号以及不用引号的区别

单引号:所见即所得,强引用。

双引号:弱引用,如果其中有命令,变量,特殊转义,会解析后再输出结果。

无引号:shell遇到空格会阶段,有可能得不到想要的

比如:

1.1 使用变量

变量名前面加美元符号即可,加{}是为了做区分 ,有时候不区分会造成混淆,都加上{}养成良好编程习惯,比如下面这种造成混淆:

bash 复制代码
for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done

for skill in Ada Coffe Action Java; do
    echo "I am good at $skillScript" #这得不到想要的结果
done

变量定义后可以重新赋值,方法是:

bash 复制代码
name="tom"
echo ${name}
name="lily"
echo ${name}
$mame="lily" #这行会报错,只有使用变量时才用$

只读变量不能被改变:

bash 复制代码
myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.runoob.com" #这行会报错

删除变量

bash 复制代码
myUrl="https://www.google.com"
readonly myUrl
name="tom"
echo ${name}
unset name
echo ${name} #会输出空行,但没报错
unset myUrl #会报错,不让删除

1.2 变量类型:

分:字符串,整数,数组,环境,特殊 这几种变量。

字符串变量 :用单引号 ' 或双引号 " 来定义字符串。
整数变量 :可以用declare声明一下,比如:declare -i my_integer=42声明告诉 Shell 将 my_integer 视为整数。
数组变量:比如:

c 复制代码
my_array=(1 2 3)
for num in "${my_arry[@]}"; do
    echo ${num}
done
bash 复制代码
#运行结果
1
2
3
c 复制代码
#关联数组变量
declare -A associative_array
associative_array["name"]="John"
associative_array["age"]=30

for element in "${associative_array[@]}"; do
    echo "$element"
done
bash 复制代码
#运行结果
30
John

1.3 环境变量

环境变量为系统或用户设置的特殊变量,用于限制行为或影响环境,常用的有:

参考博客:Tips Shell中常用的环境变量与自定义环境变量
pwd:这个在shell中断的命令也可也(在使用时,我发现这个命令只有使用小括号()括起来才有效,即$(pwd),其他形式没用 ,所以请看shell中各种括号的作用
HOME: 使用者的/~目录地址
BASH: 目前使用的shell
PATH:系统默认的可执行文件搜索路径
LANG:系统使用的编码。很多程序是根据系统指定的编码去解析输入文件,如果编码不正确,很多文件就无法正确解析。
RANDOM:随机产生一个0~32767之间的随机数

$$:表示当前shell的pid
$0:表示脚本名称
$1:表示脚本第一个参数,$2就是第二个参数

$#:为传递给shell的参数数量

$?:为上一个命令的退出状态

1.4. Shell 字符串变量

shell字符串最常用,最有用,可以单引号,双引号,也可也不用引号。刚刚我说了使用他们的区别,单引号是强转,双引号要转换一下。但是还有一些好玩的没讲:

1.4.1 字符串拼接

c 复制代码
your_name="lily"
greeting="Hi, ${your_name}."
greeting_1="Hi, \"$your_name\"."

echo ${greeting}  ${greeting_1}

结果是

c 复制代码
Hi, lily. Hi, "lily".

单引号没这效果呦。

1.4.2 获取字符串长度

其实就是加了个#号呗。

c 复制代码
string="abcde"
echo ${#string} 
echo ${#string[0]} 

结果是

c 复制代码
5
5

1.4.3 提取子字符串

c 复制代码
string="runoob is a great site"
echo ${string:2:4}
echo ${string:2:7}

string后接:索引:长度。

字符串第一个字母索的引为0,结果你猜一猜

c 复制代码
noob
noob is

1.4.3 查找字符所在位置

查找字符 i 或 o 在字符串中第几个子字母位置(第一个字母位置为0)哪个先出现就返回哪个。

c 复制代码
string="runoob is a great site"
echo `expr index "$string" is`  # 其中 ` 是反引号
echo `expr index "$string" i`  # 其中 ` 是反引号
echo `expr index "$string" s`  # 其中 ` 是反引号

答案猜一下:

c 复制代码
8
8
9

1.5 数组变量

仅支持一维数组,不支持多维。

使用下标表示成员与c语言类似。

下表中可以为数字或算数表达式。

1.5.1 定义数组

shell中用空格来定义数组,元素之间用空格分开。

c 复制代码
数组名=(值1 值2 值3 ... 值n)

可以这样定义:

c 复制代码
array_name=(
value0
value1
value2
value3
)

也可也分别定义数组的各个元素:

c 复制代码
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
array_name[7]=value7
for value in ${array_name[@]}; do
        echo ${value}
done

可以不使用连续的下标,而且下标的范围没有限制, 结果是:

c 复制代码
value0
value1
value2
value7

1.5.2 读取数组

1.5.3 获取数组的长度

获取数组成员个数,以及获取某成员长度,加 #

c 复制代码
array_name[0]=value0
array_name[1]=value01
array_name[2]=value012
array_name[7]=value01234567

length1=${#array_name[*]} #获取数组成员个数
echo "length1=${#length1}"
length2=${#array_name[@]} #获取数组成员个数
echo "length2=${#length2}"

length3=${#array_name[7]} #获取某数组成员 的 字符串长度
echo "length3=${#length3}"

echo "array_name=${array_name[@]}" #获取全部成员
echo "array_name=${array_name[*]}" #获取全部成员

揭晓答案:

c 复制代码
length1=4
length2=4
length3=13
array_name=value0 value01 value012 value01234567
array_name=value0 value01 value012 value01234567

2. Shell 注释

以 # 开头的行就是注释,会被解释器忽略。

多行注释可以是这样的,不咋用,详情看看shell注释

c 复制代码
: <<'COMMENT'
这是注释的部分。
可以有多行内容。
COMMENT

3. 传递参数

前面说了,使用美元符号加数字来传递参数。例如:

c 复制代码
不举例子了,太简单,比如:
./test.sh 11 22 33
其中test.sh中的内容为:
#!/bin/bash
echo $0
echo $1
echo $2
echo $3

运行结果为:

c 复制代码
./test.sh
11
22
33

在前面1.3一节总结了一些特殊参数,不全,再汇总一下

参数 解释
$# 脚本输入参数的个数
$* 当用""括起来,输出所有参数为"参数1 参数2 ..."
$? 判断退出状态
$! 最后运行的进程的ID号
$@ 当用""括起来,输出所有参数格式为:"参数2" "参数1" ...
$- 显示Shell使用的当前选项,与set命令功能相同
$$ shell脚本所在进程ID号

其中$*$#的不同比较难理解,看个例子就懂了:

c 复制代码
echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done
c 复制代码
#./test.sh 11 22 33
# 结果为:
-- $* 演示 ---
11 22 33
-- $@ 演示 ---
11
22
33

4. 数组

之前介绍了数组变量,咱也稍微熟悉了,知道shell中只存在一维数组,不存在高维数组。数组用括号来表示,元素之间用空格分隔,第一个元素索引为0,而且可以分别定义元素的值且可以不连续。

例子:

c 复制代码
array_name=(value1 value2 ... valuen)

读取数组元素的值:使用美元符号,养成使用{}的好习惯,格式如下:

c 复制代码
${array_name[index]}

关联数组

概念:可以使用任意字符串作为下标来访问数组元素。听着挺唬人的哈,其实就是键值对儿。直接举例子:

c 复制代码
declare -A array_name # 声明一个关联数组
array_name["xiaoming"]="good boy"
array_name["xiaohong"]="good girl"
array_name["zhangsan"]="luck dog"

echo ${array_name["xiaohong"]}

输出就是good girl

使用 @* 可以获取数组中的所有元素加上#可以获取数组成员个数或者单个成员字符个数,都在1.5 数组变量这一小节已经讲过了,去复习吧。

5. 运算符

shell中有算数,关系,布尔,字符串,文件运算符等,bash不支持简单的数学运算,但是可以通过其他命令实现,举例子用expr表达式计算工具实现两数相加:

bash 复制代码
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"
val1='expr 2 + 2' # 不是单括号,而是反引号,注意啊
echo "两数之和为 : $val1"
val2=`expr 2+2`   # 表达式与运算符之间要有空格
echo "两数之和为 : $val2" 

输出结果:

bash 复制代码
两数之和为 : 4
两数之和为 : expr 2 + 2
两数之和为 : 2+2

5.1 算数运算符

包括+ - * / % = == !=这些。但需要注意:
+ - * / % 需要用expr表达式,遵守expr表达式规范。

其中乘法*运算符需要加反斜杠\才能实现乘法运算,即:

c 复制代码
val=`expr $a \* $b`

= 经常用,两边不能有空格我就不说了。
== !=这两个条件表达式 要放在中括号[]里,且必须要有空格 ,强烈建议只能用于字符串比较,不要用于整数比较,整数比较用关系运算符(如果发现被比较对象不是数组会报警告的)。

比如:a=str, b=str, [ $a == $b ]四个空格为正确,即 取值运算必须被空格包围[$a==$b]错误[$a == $b]错误 ,就是说正确表达中空格少任何一个会报错command not found

5.2 关系运算符

关系运算符只支持数字 ,不支持字符串,除非字符串的值是数字,多用于if语句。假定变量 a=10b=20举例说明:

关系运算符 含义 举例
-eq equal [ $a -eq $b ] false
-ne not equal [ $a -ne $b ] true
-gt greater than [ $a -gt $b ]false
-lt less than [ $a -lt $b ]true
-ge greater and equal [ $a -ge $b ] false
-le less and equal [ $a -le $b ] true

5.3 布尔运算符

共三个:!-a-o., 简单猜一下哪个是取反,and运算符 ,or运算符?

恭喜你,猜对了。呱唧呱唧!

备注:用在 ... 内部组合条件(如 test 命令)

举例子:

bash 复制代码
a=10
b=300

if [$a -gt 5 -a $a -lt 15]; then
	echo "a greater than 5 and a less than 15, true"
else
	echo "a greater than 5 and a less than 15, false !"
fi

if [ $b -gt 100 -a $b -lt 200 ]; then
	echo "b greater than 100 and b less than 200, true"
else
	echo "b greater than 100 and b less than 200, false !"
fi
如果你细心的话,会发现上面的代码有一行是错误的。
且你运行会发现,这个错误不会报错没有提示。好尼玛隐蔽的错误。
提示:有一行少了两个空格,请修正代码。

下面是修正代码后的输出:

bash 复制代码
a greater than 5 and a less than 15, true
b greater than 100 and b less than 200, false !

5.4 逻辑运算符

俩:&&||,是实现逻辑AND与OR的两个命令,我新生疑惑,这跟5.3的布尔运算符不重了吗?

问题:布尔运算符 -a -o 与 逻辑运算符 && || 在使用时的差异?

答:

布尔运算符:可用于test命令,即 ... 内部。

逻辑运算符:是shell本身的逻辑与或操作符,用于连接两个独立的命令,可用于控制执行流程。

例1:

bash 复制代码
mkdir dir && cd dir  # 创建目录成功后进入
grep "hello" file.txt || echo "Not found"  # 未找到文本时提示
上面这里的逻辑运算符不能被替换为布尔运算符

例2:

bash 复制代码
if [ $b -gt 100 -a $b -lt 200 ]; then
...
上面的布尔运算符不能被替换为&&,会报错的

如果想要使用&&实现相同的逻辑有两种方法,

bash 复制代码
# 法1使用双中括号,原理参见篇首链接
if [[ $b -gt 100 && $b -lt 200 ]]; then 
# 法2,拆封成两个单独的命令,保证逻辑运算符用于连接两个单独的命令的规则
if [ $b -gt 100 ] && [ $b -lt 200 ]; then 

5.5 字符串运算符

有五个,=!=-z(长度为0),-n(长度不为0),$

分别用于:检查两个字符串,相等,不等,长度是否为0,长度是否不为0,是否为空字符串。
注意事项 1= 是 POSIX 标准,== 是 Bash 扩展,虽然都能实现字符串比较,但推荐使用=
注意事项 2 :字符串变量在test进行取值比较时,变量取值操作需要加上双引号"" ,防止字符串存在空格导致的语法错误
注意事项 3-n$都能实现检查字符串长度,但推荐使用前者,更容易理解。

举例,看看不加双引号的可能的后果:

bash 复制代码
b="a b"

if [ -n "$b" ]; then
   echo "字符串长度不为0"
fi

if [ -n "$b" ]; then
   echo "字符串长度不为0"
fi

输出,看报错了吧:

bash 复制代码
字符串长度不为0
./test.sh: line 38: [: a: binary operator expected

5.6 文件测试运算符

-c:检测文件是否字符设备
-b:检测文件是否块设备
-d:检测文件是目录
-f:是否普通文件
-r:文件是否可读
-w:文件是否可写
-x:文件是否可执行

还有一堆,看个例子吧:

bash 复制代码
if [ -d "/root/test/" ]; then
        echo "this is driectory"
fi

5.7 自增和自减操作符

本节主要讲解几点,暂时用的不多,到时候再学:

使用 let 命令进行算数运算;

使用 $(( )) 进行算术运算;

使用 expr 进行算术运算;

使用 (( )) 进行算术运算;

6. echo命令

  1. 显示普通字符串:echo "It is a test" 注意使用双引号。
  2. 显示转义字符,跟c语言的printf用法差不多echo "\"It is a test\""
  3. 显示变量:
c 复制代码
#!/bin/sh
read name  //read命令从标准输入读入一行并把值给到name变量
echo "$name"
以下为输出结果
[root@www ~]# sh test.sh
OK123     #标准输入
OK123     #输出
  1. 显示换行:
bash 复制代码
echo -e "OK! \n" # -e 开启转义
echo -e "OK! \c" # -e 开启转义 \c 不换行
  1. 重定向到文件
bash 复制代码
echo "It is a test" > myfile
  1. 单引号不进行转义
bash 复制代码
echo '$name\"'

输出结果
$name\"

7. printf命令

暂时没学,没见过

8. test命令

在 POSIX 标准中定义。 实际上是一个命令名,与 test 功能完全相同,但需要以 结尾。比如说:

bash 复制代码
[ -f "file.txt" ]  # 等价于 test -f "file.txt"

尽管功能相同,但 ... 更符合 shell 脚本的传统和可读性.
提示:无论用 test 还是 ... ,变量必须用双引号保护,防止空值或空格导致语法错误。

9. 流程控制

9.1 if 语句

写成一行适用于中断命令提示符:

c 复制代码
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
bash 复制代码
if condition1; then
    command1
elif condition2 ; then 
    command2
else
    commandN
fi

经常与 test 命令结合使用,也就是用\[\], 使用时注意到处都是空格。

9.2 for 循环

c 复制代码
for i in {1..5} ; do
    echo "The value is: $i"
done

也可换成:for ((i=1; i<5; i++)) ; do

9.3 while 循环

bash 复制代码
a=1
while [ $a -lt 5 ]; do
        echo "a = $a"
        let "a++" #也可换成 a=`expr $a + 1`
done
bash 复制代码
echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM
do
    echo "是的!$FILM 是一个好网站"
done

当while后面没东西就是无线循环了(没试):

c 复制代码
while :
do
    command
done

9.4 until 循环

使用 until 命令来输出 0 ~ 9 的数字:

bash 复制代码
b=0
until [ $b -gt 9 ]; do
        echo "b = $b"
        let "b++" #也可换成b=`expr $b + 1`
done

9.5 case 语句

case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,记住结构:

bash 复制代码
#!/bin/sh

site="google"

case "$site" in
   "baidu") echo "百度"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘宝网"
   ;;
esac

9.6 break 与 continue

break 命令允许跳出所有循环(终止执行后面的所有循环)。

continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

10. 函数

11. 输入输出重定向

12. 文件包含

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5203 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩3 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言