Shell脚本详解
浏览:70
评论:0
前言
shell英文翻译过来是外壳的意思,作为计算机语言来理解可以认为它是操作系统的外壳。shell是站在内核的基础上编写的一个应用程序,它连接了用户和Linux内核,从而让用户能够更加便捷、高效、安全的使用linux内核,这其实就是shell的本质。我们可以通过shell命令来操作和控制操作系统,比如Linux中的shell命令就包括ls、cd、pwd等等。
1、什么是shell脚本
shell脚本就是由Shell命令组成的执行文件
,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。shell脚本可以记录命令执行的过程和执行逻辑,以便以后重复执行,还可以批量、定时处理主机,方便管理员进行设置或者管理。
2、创建一个简单的shell脚本
- Linux 的 Shell 种类众多,目前常用且免费的是Bash(全称 Bourne Again Shell)。Bash 也是大多数Linux 系统默认的 Shell。
- 打开编辑器,创建一个test.sh文件,扩展名为 sh(sh代表shell)。扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了。
- #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
#!/bin/bash
echo "Hello World !"
3、运行shell脚本
运行 Shell 脚本有两种方法:
- 作为可执行程序
# cd 到 test.sh 目录下
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
- 作为解释器参数
# 直接运行解释器,其参数就是 shell 脚本的文件名
/bin/sh test.sh
# 等价
/bin/bash test.sh
# 这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
4、shell脚本语法
变量
在定义变量时,变量名和等号之间不能有空格。 变量命名规则需要遵循如下规则:
- 只包含字母、数字和下划线
- 不能以数字开头
- 避免使用 Shell 关键字
- 使用大写字母表示常量
- 避免使用特殊符号。
- 避免使用空格: 变量名中不应该包含空格,因为空格通常用于分隔命令和参数。
# 字符串变量, 可以使用单引号 ' 或双引号 " 来定义字符串
_str = '字符串变量'
_str1 = "字符串变量${_str}" # 双引号里可以包含变量,该变量会被解析。还可以使用转义字符。
# 字符串变量拼接
str1 = "${_str}拼接${_str1}"
# 字符串变量长度
echo ${#str1}
# 字符串变量截取,${string: start :length} start 是起始位置(从左边开始,从 0 开始计数)length 是要截取的长度(省略的话表示直到字符串的末尾)
echo ${str1: 1: 9} # 从1到9
# 还可以使用,右边截取0-、“#”截取、“%”截取
# 整数变量, 可以使用 declare 或 typeset 命令来声明整数变量。如果尝试将非整数值赋给它,Shell会尝试将其转换为整数。
declare -i test_num=53
test_num="vscing"
# 数组变量,定义数组的一般形式为:array_name=(ele1 ele2 ele3 … elen)
arr=(3 5 "vscing")
# 利用 @或 *,可以将数组扩展成列表,然后使用 #来获取数组元素的个数
echo ${#arr[*]}
echo ${#arr[@]} # 等价上面
# 数组前加一个感叹号 ! 可以获取数组的所有键
echo "数组的键为: ${!arr[*]}"
echo "数组的键为: ${!arr[@]}"
echo ${#arr[1]} # 输出第2个元素
# 环境变量
echo $PATH
# 特殊变量: 有一些特殊变量在 Shell 中具有特殊含义,例如 $0 表示脚本的名称,$1, $2, 等表示脚本的参数。$#表示传递给脚本的参数数量,$? 表示上一个命令的退出状态等。
在变量被使用时候,变量名前缀需要加
$
符号
_url="https://tool.vscing.com"
echo $_url
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变
_data="我是只读变量"
readonly _data
_data="我重新赋值是错误的"
使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。
_data1="我是测试删除变量"
unset _data1
_data="我被删除了,不能再使用了"
函数
shell 可以用户定义函数,然后在shell脚本中可以随便调用。
- 函数返回值在调用该函数后通过 $? 来获得。
- 函数定义必须在使用之前
- return 语句只能返回一个介于 0 到 255 之间的整数
funWithReturn(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn 1 2
echo "输入的两个数字之和为 $? !"
# 第一个参数为 1 !
# 第二个参数为 2 !
# 这个函数会对输入的两个数字进行相加运算...
# 输入第一个数字:
# 1
# 输入第二个数字:
# 2
# 两个数字分别为 1 和 2 !
# 输入的两个数字之和为 3 !
Shell 传递参数
- 定义一个test.sh脚本
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
- 加上可执行权限,并执行
chmod +x test.sh
./test.sh 1 2 3
# Shell 传递参数实例!
# 执行的文件名:./test.sh
# 第一个参数为:1
# 第二个参数为:2
# 第三个参数为:3
参数处理 | 说明 |
---|---|
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数 |
$- | 显示Shell使用的当前选项,与set命令功能相同 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误 |
echo、printf、test
- Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。
echo "Hello, Shell"
- printf 命令模仿 C 程序库(library)里的 printf() 程序
printf "Hello, Shell\n"
- Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
基本运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
- 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2。
- 完整的表达式要被
- 乘号(*)前边必须加反斜杠()才能实现乘法运算。
- 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "" 。
算术运算符
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=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi
布尔运算符
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi
逻辑运算符
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
字符串运算符
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi
文件测试运算符
#test.sh 具有 rwx 权限
file="/var/www/vscing/test.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
Shell 流程控制
# if elseif else
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
# for 循环
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
# while 语句
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
# until 循环 执行一系列命令直至条件为 true 时停止。和while 语句相反
a=0
until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done
# switch ... case语句
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
# 跳出循环 break 命令 continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
5、shell脚本重定向、文件包含
输入/输出重定向
在Shell中,输入/输出重定向是一种控制程序的方式,它允许我们以不同的方式与程序进行交互。以下是一些常用的输入/输出重定向方法:
标准输入(stdin):代码为0,通常用于读取输入。
标准输出(stdout):代码为1,用于输出正确的信息。
标准错误(stderr):代码为2,用于输出错误信息。
重定向的基本操作符有:
>
:将stdout或stderr的内容重定向到文件中,如果文件已存在则覆盖它。>>
:将stdout或stderr的内容追加到文件中。<:将文件的内容重定向到stdin。
2>:将stderr的内容重定向到文件中,如果文件已存在则覆盖它。
2>>:将stderr的内容追加到文件中。
&>:将stdout和stderr的内容重定向到文件中,如果文件已存在则覆盖它。
&>>:将stdout和stderr的内容追加到文件中。
# 将echo命令的输出重定向到文件中
echo "Hello World" > output.txt
# 将ls命令的错误信息重定向到文件中
ls non_existing_file 2> error.txt
# 将ls命令的输出和错误信息重定向到同一个文件中
ls non_existing_file &> output_and_error.txt
# 将cat命令的输入来自于文件
cat < input.txt
# 将find命令的输出追加到文件中
find . -name "*.txt" >> files.txt
文件包含
#使用 . 号来引用同目录下的 test2.sh 文件
. ./test2.sh
echo "end"