Shell:脚本编程语言

6.Shell 脚本编程语言 学习记录

Shell 简介

Shell 首先是 UNIX/Linux 下的脚本编程语言,它是解释执行的,无需提前编译。Shell 的语法细节和你熟悉的大部分编程语言都不太一样,需要重点学习。

Shell 同时也是一个程序,它的一端连接着 UNIX/Linux 内核,另一端连接着用户和其它应用程序;换句话说,Shell 是用户和应用程序与内核沟通的桥梁。

一、Shell 教程

第一个Shell脚本

  1. 创建Shell脚本文件

    touch 1-first.sh
    
  2. 编辑文件

    vi 1-first.sh
    
    • 输入以下内容
      	#!/bin/bash
      	echo "Hello World !"
      
  3. 修改权限(使脚本具有执行权限)

    chmod 775 1-first.sh
    
  4. 运行脚本

     ./1-first.sh
    

二、Shell 变量

2.1 定义变量

变量名不加美元符号($,PHP语言中变量需要),如:

your_name="KissedBySnow"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

2.2 使用变量

#变量赋值(可以多次赋值)
variable="aaa"

#删除变量
unset variable

#定义只读变量,只读变量不可修改,不可删除
variable="bbb"
readonly variable

三、Shell 字符串

3.1 单双引号的区别

字符串的类型:单双引号的区别跟PHP类似。
单引号
双引号
不使用引号
name="Troy"

# 使用单引号拼接(单引号里的字符都会原样输出,即便是变量也是无效的)
a1='hello, '$name' !' #输出 hello, Troy !
a2='hello, ${name} !' #输出 hello, ${name} !
echo $a1  $a2

# 使用双引号拼接(双引号里可以有变量)
b1="hello, "$name" !" #输出 hello, Troy !
b2="hello, ${name} !" #输出 hello, Troy !
echo $b1  $b2

3.2 获取字符串长度

string="abcd"
echo ${#string} #输出 4

3.3 提取子字符串

以下实例从字符串第 2 个字符开始截取 4 个字符:

string="runoob is a great site"
echo ${string:1:4} # 输出 unoo

3.4 查找子字符串

查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

注意: 以上脚本中 ` 是反引号,而不是单引号 '。

四、Shell 数组

bash仅支持一维数组,不限定数组大小。数组元素的下标由0开始。

4.1 定义数组

Shell中,使用括号来表示数组,数组元素用“空格”符号分隔开。定义数组的一般形式为:

数组名=(值1 值2 ... 值n)

例如:

array=(value0 value1 value2 value3 value4)

或者

array=(
value0
value1
value2
value3
)

还可以单独定义数组的各个分量:

array[0]=value0
array[1]=value1

可以不使用连续的下标,而且下标的范围没有限制。

4.2 读取数组

读取数组元素值的一般格式是:

${数组名[下标]}

例如:

aaa=${array_name[2]}

使用 @ 符可以获取数组中的所有元素,例如:

echo ${array_name[@]}
echo ${array_name[*]} # *符也可以

4.3 获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同,例如:

# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}

# 取得数组单个元素的长度
lengthn=${#array_name[n]}

五、Shell 注释

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

  1. 如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?
    可以用 {} 括起来,这样就定义成了一个函数,但是不调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
  2. 多行注释还可以使用以下格式:
    :<<EOF
    注释内容...
    注释内容...
    注释内容...
    EOF
    # EOF 也可以使用其他符号代替:
    
    :<<'
    注释内容...
    注释内容...
    注释内容...
    '
    
    :<<!
    注释内容...
    注释内容...
    注释内容...
    !
    

六、参数传递

实例1:实现两个数的相加

touch addition.sh
vi addition.sh
#!/bin/bash
echo `expr $1 + $2` #这是一个加法公式,传入两个参数并相加后,输出。输出结果:3
echo $0 #输出执行的文件名
chmod 770 addition.sh 
./addition.sh 1 2

输出结果:

3
./addition.sh

在这里插入图片描述

#!/bin/bash

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
echo "传递的参数作为多个字符串显示:$@";
[yzy@localhost shell练习区]$ ./3.sh 99 88 77
Shell 传递参数实例!
执行的文件名:./3.sh
第一个参数为:99
第二个参数为:88
第三个参数为:77
参数个数为:3
传递的参数作为一个字符串显示:99 88 77
传递的参数作为多个字符串显示:99 88 77

$* 与 $@ 区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
#!/bin/bash

echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done
[yzy@localhost shell练习区]$ ./4.sh 99 88 77
-- $* 演示 ---
99 88 77
-- $@ 演示 ---
99
88
77

七、运算符

7.1 算术运算符

$ echo $[1+2]
3

$ echo `expr 1 + 2`
3

$[1+2] 等价于 `expr 1 + 2`

  • $[] 个人认为比expr好用,至于有没有区别我还不知道。
  • expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
    • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
    • 完整的表达式要被 `   ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。

下表列出了常用的算术运算符,假定 a=10 b= 20

运算符说明举例解释
+加法`expr $a + $b`结果为 30
-减法`expr $a - $b`结果为 -10
*乘法`expr $a \* $b`结果为 200
/除法`expr $b / $a`结果为 2
%取余`expr $b % $a`结果为 0
=赋值a=$b将把变量 b 的值赋给 a
==两数相等返回 true。[ $a == $b ]返回 false
!=两束不相等返回 true。[ $a != $b ]返回 true

注意1: 条件表达式要放在方括号之间,并且要有空格。例如:
[$a==$b] 是错误的
[ $a == $b ] 是正确的

注意2:
乘号(*)前边必须加反斜杠(\)才能实现乘法运算;

实例:

#!/bin/bash

a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi

结果:

a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b

7.2 关系运算符

运算符说明举例
-eq检测两个数是否相等,相等返回 true。[ $a -eq $b ] 返回 false。
-ne检测两个数是否不相等,不相等返回 true。[ $a -ne $b ] 返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。[ $a -gt $b ] 返回 false。
-lt检测左边的数是否小于右边的,如果是,则返回 true。[ $a -lt $b ] 返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 false。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true。

7.3 布尔运算符

运算符说明举例
!非运算,表达式为 true 则返回 false,否则返回 true。[ ! false ] 返回 true。
-o或运算,有一个表达式为 true 则返回 true。[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-a与运算,两个表达式都为 true 才返回 true。[ $a -lt 20 -a $b -gt 100 ] 返回 false。

7.4 逻辑运算符

运算符说明举例
&&逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
||逻辑的 OR[[ $a -lt 100 || $b -gt 100 ]] 返回 true

7.5 字符串运算符

运算符说明举例
=检测两个字符串是否相等,相等返回 true。[ $a = $b ] 返回 false。
!=检测两个字符串是否相等,不相等返回 true。[ $a != $b ] 返回 true。
-z检测字符串长度是否为0,为0返回 true。[ -z $a ] 返回 false。
-n检测字符串长度是否为0,不为0返回 true。[ -n “$a” ] 返回 true。
$检测字符串是否为空,不为空返回 true。[ $a ] 返回 true。

7.6 文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。

操作符说明举例
-b file检测文件是否是块设备文件,如果是,则返回 true。[ -b $file ] 返回 false。
-c file检测文件是否是字符设备文件,如果是,则返回 true。[ -c $file ] 返回 false。
-d file检测文件是否是目录,如果是,则返回 true。[ -d $file ] 返回 false。
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。[ -f $file ] 返回 true。
-g file检测文件是否设置了 SGID 位,如果是,则返回 true。[ -g $file ] 返回 false。
-k file检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。[ -k $file ] 返回 false。
-p file检测文件是否是有名管道,如果是,则返回 true。[ -p $file ] 返回 false。
-u file检测文件是否设置了 SUID 位,如果是,则返回 true。[ -u $file ] 返回 false。
-r file检测文件是否可读,如果是,则返回 true。[ -r $file ] 返回 true。
-w file检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-x file检测文件是否可执行,如果是,则返回 true。[ -x $file ] 返回 true。
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true。
-e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true。
#!/bin/bash

file="/home/yzy/shell练习区/1-first.sh"

if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi

if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi

if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi

if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi

if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi

if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi

if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi
[yzy@localhost shell练习区]$ ./5-fifth 
文件可读
文件可写
文件可执行
文件为普通文件
文件不是个目录
文件不为空
文件存在

八、Shell echo 命令

1.显示普通字符串:

echo "It is a test"

这里的双引号完全可以省略,以下命令与上面实例效果一致:

echo It is a test

2.显示转义字符

echo "\"It is a test\""
echo  \"It is a test\" 

结果将是:

"It is a test"
"It is a test"

3.显示变量
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

#!/bin/sh
read name 
echo "$name It is a test"

以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:

[root@www ~]# sh test.sh
OK                     #标准输入
OK It is a test        #输出

4.显示换行

echo -e "OK! \n" # -e 开启转义
echo "It is a test"

输出结果:

OK!

It is a test

5.显示不换行

#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"

输出结果:

OK! It is a test

6.显示结果定向至文件

echo "It is a test" > myfile

7.原样输出字符串,不进行转义或取变量(用单引号)

echo '$name\"'

输出结果:

$name\"

8.显示命令执行结果

echo `date`

注意: 这里使用的是反引号 `, 而不是单引号 '。
结果将显示当前日期

2019年 04月 23日 星期二 22:05:50 CST

九、Shell printf 命令

printf 命令格式:

printf "类型+格式" 输出内容
english输出类型解释
Char%c字符
String%s字符串
Decimal%d十进制整数
Integer%i整数
Float%f浮点数
  • %-8s 指一个宽度为8个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在8个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
  • %-4.2f 指格式化为小数,其中.2指保留2位小数。
输出格式解释
\n换行
\a输出警告声音
\b输出退格键,也就是 Backspaced 键
\f清除屏幕
\r回车,也就是 Enter 键
\t水平输出退格键,也就是 Tab 键
\v垂直输出退格键,也就是 Tab 键

实例1:

#!/bin/bash

# 单引号与双引号效果一样 
printf "%d %s\n" 1 "aaa"
printf '%d %s\n' 1 "aaa"

# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf "%s\n" c c c

printf "%i %i %i\n" 1 2 3 4 5 6 7 8 9

# 如果没有 输出内容,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"

# 没有引号也可以输出,但是换行符就不能用了
printf %s\n bbb

$ ./6-sixth.sh 
1 aaa
1 aaa
c
c
c
1 2 3
4 5 6
7 8 9
 and 0 
bbbn

实例2:
简单调用:

[yzy@localhost shell练习区]$ printf "<%s>\t" A B C D
<A>	<B>	<C>	<D>	

实例3:
调用文件中的内容

$ vi student.txt

ID Name PHP Linux MySQL Average
1 Liming 82 95 86 87.66
2 Sc 74 96 87 85.66
3 Gao 99 83 93 91.66
$ printf '%2s %8s %8s %8s %8s %8s \n' $(cat student.txt)
ID     Name      PHP    Linux    MySQL  Average 
 1   Liming       82       95       86    87.66 
 2       Sc       74       96       87    85.66 
 3      Gao       99       83       93    91.66 
 

去掉表头(第一行标题):

$ printf '%2i %8s %8i %8i %8i %8.2f \n' $(cat student.txt|grep -v Name)
 1   Liming       82       95       86    87.66 
 2       Sc       74       96       87    85.66 
 3      Gao       99       83       93    91.66 

十、Shell test 命令

https://www.runoob.com/linux/linux-shell-test.html

十一、Shell 流程控制

if else

  1. if
    if condition
    then
        command1 
        command2
        ...
        commandN 
    fi
    
  2. if else
    if condition
    then
        command1 
        command2
        ...
        commandN
    else
        command
    fi
    
  3. if else-if else (if elif else)
    if condition1
    then
        command1
    elif condition2 
    then 
        command2
    else
        commandN
    fi
    

for

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

例,顺序输出当前列表中的数字:

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

输出结果:

The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

while

while condition
do
    command
done

无限循环

while :
do
    command
done
while true
do
    command
done
for (( ; ; ))

until

until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

until condition
do
    command
done

condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环。
以下实例我们使用 until 命令来输出 0 ~ 9 的数字:

#!/bin/bash

a=0
until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

输出结果为:

0
1
2
3
4
5
6
7
8
9

case

casein
模式1)
    command
    ;;
模式2)
    command
    ;;
*)
	command
	;;
esac

注意:

  • 取值后面必须为单词in
  • 每个case分支用右圆括号
  • 用两个分号表示break。
  • 它需要一个esac(就是case反过来)作为结束标记

下面的脚本提示输入1到4,与每一种模式进行匹配:

echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac
输入 1 到 4 之间的数字:
你输入的数字为:
3
你选择了 3

跳出循环 break (跳出所有循环)

break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

#!/bin/bash
while :
do
    echo -n "输入 1 到 5 之间的数字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
            break
        ;;
    esac
done

while循环将一直调用,break命令跳出case while两层循环。

输入 1 到 5 之间的数字:3
你输入的数字为 3!
输入 1 到 5 之间的数字:7
你输入的数字不是 1 到 5 之间的! 游戏结束

跳出循环 continue (仅跳出本次循环)

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

#!/bin/bash
while :
do
    echo -n "输入 1 到 5 之间的数字: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的!"
            continue
            echo "游戏结束"
        ;;
    esac
done

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “游戏结束” 永远不会被执行。

十二、Shell 函数

https://www.runoob.com/linux/linux-shell-func.html
函数返回值在调用该函数后通过 $? 来获得

十三、输入/输出重定向

https://www.runoob.com/linux/linux-shell-io-redirections.html

十四、文件包含

shell可以包含外部脚本,这样可以很方便的封装一些独立的代码文件。
语法格式:

. fileName	#注意点号.和文件名之间有一个空格

或者

source fileName

实例: 创建两个shell脚本
test1.sh

#!/bin/bash
url="blog.csdn.net/KissedBySnow/"

test2.sh

#!/bin/bash
. ./test1.sh	#使用.来引用test1.sh
echo "地址:$url"

接下来,我们为 test2.sh 添加可执行权限并执行:

$ chmod +x test2.sh 
$ ./test2.sh 
地址:blog.csdn.net/KissedBySnow/
  • 1
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

KissedBySnow

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值