Linux Shell编程

Shell概述

什么是Shell

Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

![image-20221107211833782](Linux Shell编程/image-20221107211833782.png)

什么是Shell脚本

Shell脚本,是一种为shell编写的脚本程序。

业界所说的shell, 通常都是指shell脚本,但是shell 和 shell 脚本是两个不同的概念。

Shell的环境

Shel 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了

Linux 的 Shell 种类众多,常见的有:

  • 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

一般情况下人们并不区分Bourne Shell和Bourne Again Shell, 所以像#!/bin/sh也可以改成#!/bin/bash

#!表示告诉系统其后路径所指定的程序就是解析脚本文件的Shell程序

Shell脚本入门

脚本格式

脚本#!/bin/bash开头, 表示指定解析器

脚本执行的三种方式

首先创建一个简单的Shell脚本, 用于输出"helloworld"

[root@localhost herry]# touch helloworld.sh
[root@localhost herry]# vim helloworld.sh 
[root@localhost script]# cat helloworld.h 
#!/bin/bash
a="helloworld"
echo $a

1.bash或sh + 脚本路径

sh + 脚本的相对路径或绝对路径

[root@localhost herry]# sh ./helloworld.sh 
helloworld
[root@localhost herry]# sh /home/herry/script/helloworld.sh
helloworld

bash + 脚本的相对路径或绝对路径

[root@localhost herry]# bash helloworld.sh 
helloworld
[root@localhost herry]# bash /home/herry/script/helloworld.sh 
helloworld

2.直接输入脚本的路径执行

首先赋予helloworld.sh可执行权限

[root@localhost herry]# chmod +x helloworld.sh 

然后再执行脚本, 以下分别使用相对路径和绝对路径执行

[root@localhost script]# ./helloworld.h 
helloworld
[root@localhost script]# /home/herry/script/helloworld.h 
helloworld

3.在脚本路径前加上.或者source

此处将helloworld.sh脚本文件内容修改成如下所示:

[root@localhost script]# cat helloworld.h 
#!/bin/bash
echo $my_var

前两种方式都是在当前Shell中打开一个子Shell来执行脚本, 脚本执行完毕后, 则子Shell关闭, 回到父Shell中

以下代码使用前两种方式执行脚本, 均无任何输出, 这是因为$my_var变量作用于父Shell, 子shell是无法访问该变量的, 若想访问则需使用关键字export将该变量定义成全局变量。

[root@localhost script]# my_var="helloworld"
[root@localhost script]# ./helloworld.h 

[root@localhost script]# bash ./helloworld.h 

[root@localhost script]# export my_var
[root@localhost script]# ./helloworld.h 
helloworld

而第三种方式可以使用当前Shell来执行脚本, 而无需新打开一个子Shell, 因此$my_var变量是可以访问的

[root@localhost script]# . helloworld.h 
helloworld

变量

1.系统预定义变量

常用系统变量

$HOME$PWD$SHELL$USER等等

使用实例

  • 查看系统变量的值

[root@localhost herry]# echo $HOME
/root
  • 显示Shell中所有的变量

[root@localhost herry]# set
ABRT_DEBUG_LOG=/dev/null
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()

2.自定义变量

基本语法

  • 定义变量: 变量名=变量值 (注意:等号前后不能有空格)

  • 撤销变量: unset 变量名

  • 声明静态变量: readonly 变量名 (此变量不能unset)

变量定义规则

  • 变量名称由字母、数字和下划线组成, 不能以数字开头

  • 等号两侧不能由空格

  • 在bash中, 变量默认为字符串类型, 无法进行数值运算

使用实例

1.给变量A赋值

[root@localhost script]# a=5
[root@localhost script]# echo $a
5

2.撤销变量A

[root@localhost script]# unset a
[root@localhost script]# echo $a

3.声明静态变量b, 不能unset

[root@localhost script]# readonly b=1
[root@localhost script]# b=9
bash: b: 只读变量
[root@localhost script]# echo $b
1

4.在bash中变量默认类型均为字符串类型, 无法进行数值运算

[root@localhost script]# c=1+1
[root@localhost script]# echo $c
1+1

5.将变量提升为全局变量, 可供其他Shell使用

[root@localhost script]# cat helloworld.h 
#!/bin/bash
echo $my_var
[root@localhost script]# export my_var="helloworld"
[root@localhost script]# ./helloworld.h 
helloworld

3.特殊变量

$n

n为数字, $0表示该脚本的名称, $1-$9代表第一到第九个参数, 第十及以以上的参数要用大括号包含, 如${10}

[root@localhost script]# cat test.sh 
#!/bin/bash
echo '===$n==='
echo $0
echo $1
echo $2
[root@localhost script]# chmod 777 test.sh 
[root@localhost script]# ./test.sh henry 666
===$n===
./test.sh
henry
666
[root@localhost script]# /home/herry/script/test.sh henry 666
===$n===
/home/herry/script/test.sh
henry
666

$#

$#表示获取输入参数的个数, 常用于循环以及判断参数个数是否正确

[root@localhost script]# cat test.sh 
#!/bin/bash
echo '===$n==='
echo $0
echo $1
echo $2
echo '===$#==='
echo $#
[root@localhost script]# ./test.sh henry 666
===$n===
./test.sh
henry
666
===$#===
2

$*$@

  • $*: 把所有的参数看成一个整体

  • $@: 将所有的参数看成一个列表, 后续可用于遍历

[root@localhost script]# cat test.sh 
#!/bin/bash
echo '===$n==='
echo $0
echo $1
echo $2
echo '===$#==='
echo $#
echo '===$*==='
echo $*
echo '===$@==='
echo $@
[root@localhost script]# ./test.sh a b c d e
===$n===
./test.sh
a
b
===$#===
5
===$*===
a b c d e
===$@===
a b c d e

$?

$?表示最后一次执行命令的返回状态。若值为0, 表示上一个命令执行正确; 若值非0, 表示上一个命令执行错误

[root@localhost script]# ./test.sh 
===$n===
./test.sh

===$#===
0
===$*===

===$@===

[root@localhost script]# echo $?
0
[root@localhost script]# test.sh
bash: test.sh: 未找到命令...
[root@localhost script]# echo $?
127

运算符

运算表达式

  • $[表达式]

  • $((表达式))

使用实例

[root@localhost script]# vim add.sh
[root@localhost script]# chmod +x add.sh 
[root@localhost script]# cat add.sh 
sum=$[$1+$2]
echo $sum
[root@localhost script]# ./add.sh 1 2
3
[root@localhost script]# echo $((1+5))
6
[root@localhost script]# echo $[1+5]
6

条件判断

基本语法

  • test condition

  • [ condition ] (==注意condition前后两边要有空格==)

与其他编程语言不同的是, 条件为True时, echo $?返回值为0; 条件为False时, echo $?返回值为1;

常用判断条件

1.整数之间的比较

  • -eq=: 等于(equal)

  • -ne!=: 不等于(not equal)

  • -lt: 小于(less than)

  • -gt: 大于(greater than)

  • -le: 小于等于(less equal)

  • -ge: 大于等于(greater equal)

2.文件权限判断

  • -r: 是否有可读权限

  • -w: 是否有可写权限

  • -x: 是否有可执行权限

3.文件类型判断

  • -e: 文件是否存在

  • -f: 文件是否存在且为常规文件

  • -d: 文件是否存在且为目录

使用实例

1.判断整数之间的大小

[root@localhost herry]# test 1=1
[root@localhost herry]# echo $?
0

[root@localhost herry]# [ 1 = 1 ]
[root@localhost herry]# echo $?
0

[root@localhost herry]# [ 1 = 2 ]
[root@localhost herry]# echo $?
1

[root@localhost herry]# [ 1 != 2 ]
[root@localhost herry]# echo $?
0

[root@localhost script]# [ 1 -lt 2 ]
[root@localhost script]# echo $?
0

注意: 等号两边也得有空格, 不然会报错

2.判断shell.sh文件是否有可执行权限

[root@localhost script]# [ -x shell.sh  ]
[root@localhost script]# echo $?
1

3.判断/home/herry/script/shell.sh文件是否存在

[root@localhost script]# [ -f /home/herry/script/shell.sh  ]
[root@localhost script]# echo $?
0

4.多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令; || 表示上一 条命令执行失败后,才执行下一条命令)

[root@localhost script]# [ 1 -lt 2 ] && echo True || echo False
True
[root@localhost script]# [ ] && echo True || echo False
False

流程控制

if判断

基本语法

注意: if后要有空格

  • 单分支

if [ 条件判断 ] 
then
  程序
fi
  • 多分支

if [ 条件判断 ] 
then
  程序
else
  程序
fi
if [ 条件判断 ] 
then
  程序
elif [ 条件判断 ]
then
  程序
else
  程序
fi

使用实例

输入一个数字, 如果数字是1则输出"This is 1", 否则输出"This not 1"

[root@localhost script]# cat ./script.sh 
#!/bin/bash
if [ $1 = 1 ]
then
  echo "This is 1"
else
  echo "This not 1"
fi
[root@localhost script]# ./script.sh 1
This is 1

输入一个字符串, 若此字符串是"henry"则输出"This is henry", 否则输出"This not henry"

[root@localhost script]# cat script.sh 
#!/bin/bash
if [ "$1"x = "henry"x ]
then
  echo "This is henry"
else
  echo "This not henry"
fi
[root@localhost script]# ./script.sh henry
This is henry

$1后面拼接字符串'x'的目的是, 当$1的值为空时,"x"就不等于"henryx", 则会输出"This is not henry", 而不会出现报错

case语句

基本语法

case $var in
"值1")
	若变量值为"值1",执行此程序
;;
"值2")
	若变量值为"值2",执行此程序
;;
...
*)
	若变量值都不是以上的值,执行此程序
;;
esac
  • 双分号;;相当于C语言的break

  • 最后的*)相当于C语言的dafault

  • 最后的esac其实就是case反过来的形式, 代表case语句的结束

使用范例

输入一个数字, 若为1则输出"This is henry"; 若为"henry"则输出"This is henry"; 若上述都不是则输出"This is nothing"

[root@localhost script]# cat script.sh 
#!/bin/bash
case $1 in
1)
  echo "This is 1"
;;
"henry")
  echo "This is henry"
;;
*)
  echo "This is nothing"
;;
esac
[root@localhost script]# ./script.sh 1
This is 1
[root@localhost script]# ./script.sh henry
This is henry
[root@localhost script]# ./script.sh what
This is nothing

for循环

基本语法

  • for循环语法1

for (( 初始值;循环条件;变量变化))
do
	程序
done
  • for循环语法2(更常用)

for var in value1 value2 value3
do
	程序
done

使用实例

1.输入一个数字n, 输出从1加到n的总和

注意此处变量sum赋值的时候不用添加$, 但是引用的时候需要添加$

[root@localhost script]# cat ./script.sh 
#!/bin/bash

sum=0
for (( i=0;i<=$1;i++))
do
  sum=$[$sum+$i]
done
echo $sum
[root@localhost script]# ./script.sh 100
5050

2.打印所有输入的参数

[root@localhost script]# cat script.sh 
#!/bin/bash

sum=0
for i in $1 $2 $3
do
  echo $i
done
[root@localhost script]# ./script.sh henry tom terry
henry
tom
terry

while循环

基本语法

while [ 条件判断式 ]
do
	循环代码
done

使用实例

从1加到100(要注意赋值表达式之间没有空格)

sum=0
i=1
while [ $i -le 100 ]
do
	sum=$[$sum+$i]
    i=$[$i+1]
done

echo $sum

read命令

基本语法

read 是一个用于从标准输入读取数据的命令, 可以通过键盘输入获取数据

命令语法格式如下, options 表示一些可选参数, variable 是一个或多个变量名,用于存储从标准输入读取的数据

read [-options] [variable ...]

read命令的常用参数如下:

  • -p: 指定读取值时的提示符

  • -t: 指定超时时间

使用实例

在7秒内读取键盘输入的值并输出

#!/bin/bash
read -p "在7秒内输入一个数字:" -t 7 input
echo $input

执行结果如下:

[root@henry test]# ./test.sh
请输入一个数字:66
66

系统函数

basename

基本语法

basename 是一个在 Unix/Linux 系统中常用的命令,用于获取一个文件或路径的基本名称, 其语法格式如下:

basename string [suffix]		

其中,string 参数可以是一个文件名或路径,suffix 参数是一个可选的后缀,表示要删除的后缀部分

使用实例

$ basename /usr/local/bin/python.exe
python.exe

$ basename /usr/local/bin/python.exe .exe
python

dirname

基本语法

dirname命令用于从给定包含绝对路径的文件名去除文件名, 然后返回剩余的路径, 简单来说就是获取文件的所在目录

使用实例

[root@henry test]# dirname /usr/bin/python.exe
/usr/bin

自定义函数

基本语法

若添加了return来获取函数返回值, 那么函数的返回值只能通过$?系统变量获取;若不添加return, 则以最后一条命令作为运行结果,return后跟数值

function 函数名{
	函数代码
	return 返回值
}

使用实例

1.一个简单的加法函数, 有两种方法, 分别是使用return和不使用return

#!/bin/bash

function sum() {
  return $(($1 + $2))
}

echo "请输入两个值:"
read var1 var2
sum $var1 $var2
result=$?
echo $result
#!/bin/bash

function sum() {
  echo $(($1 + $2))
}

echo "请输入两个值:"
read var1 var2
result=$(sum $var1 $var2)
echo $result

2.通过遍历来获取指定格式文件的数量

#!/bin/bash

# Define a custom function
function count_files {
    local dir=$1  #使用local来定义局部bian'liang
    local ext=$2
    local count=0
    for file in "$dir"/*."$ext"; do
        if [ -f "$file" ]; then
            count=$((count+1))
        fi
    done
    echo "$count"
}

# Call the custom function
num_files=$(count_files /path/to/directory txt)
echo "There are $num_files text files in the directory."

最后更新于