欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

shell脚本学习笔记

程序员文章站 2022-05-02 13:00:25
shell脚本的格式 shell脚本默认文件扩展名为 。在shell脚本中,你写入的内容,会默认当成一条命令来执行。 例如: 第1行 指定shell脚本的默认解释器 第2行 执行echo命令 将上面的代码存为test.sh,并将可执行权限赋予它 ,执行 运行脚本。 上面的脚本将会输出: 注释 和所有 ......

shell脚本的格式

shell脚本默认文件扩展名为.sh。在shell脚本中,你写入的内容,会默认当成一条命令来执行。
例如:

#!/bin/bash
echo 'hello world'
  • 第1行 指定shell脚本的默认解释器
  • 第2行 执行echo命令

将上面的代码存为test.sh,并将可执行权限赋予它chmod +x test.sh ,执行./test.sh运行脚本。

上面的脚本将会输出:

hello world

注释

和所有的编程语言一样,shell也有注释,在shell中,#号和它后面的内容来表示一个注释:

# print a message
echo "i'm a shell script."

输出内容

echo用于向输出流输出内容,例如:

echo "hello world"

输入内容

read关键字用于输入一条内容:

read input
echo $input

上面的代码中,read关键字从输入流读取一个值并赋予input,然后将input的内容打印出来

1. 变量

定义变量和赋值

变量的命名规则和c语言差不多,支持英文字母和下划线。shell中变量名前不需要声明类型,变量名后面不能有空格,例如:

var1='hello'
var2=90

读取变量

$后接变量名意为读取一个变量的值,例如:

var="hello"
echo $var

也可以用${var}方式访问到变量值,例如:

var="hello"
echo ${var}

访问变量的时候$var${var}是等效的,推荐后者来访问一个变量

变量作用域

全局变量

没有任何关键字修饰的变量是一个全局变量,全局变量在同一个shell会话中都是有效的。可以跨文件

function func(){
    a=90
}
func
echo $a

输出:

90

$ a=90
$ echo ${a}
$ bash 
$ echo ${a}

输出:

90

空值

局部变量

local关键字用于声明一个局部变量

function func(){
    local a=90
}
func
echo $a

输出:

空值

环境变量

用export关键字修饰的变量称为环境变量,在父shell会话中声明一个环境变量,子shell中都可以访问

$ export path="/system/bin"
$ bash #创建一个新的shell会话
$ echo ${path}

特殊变量

变量 含义
$0 当前脚本的文件名
$n(n≥1) 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2
$# 传递给脚本或函数的参数个数
$* 传递给脚本或函数的所有参数
$@ 传递给脚本或函数的所有参数
$? 上个命令的退出状态,或函数的返回值
$$ 当前 shell 进程 id。对于 shell 脚本,就是这些脚本所在的进程 id

$*和$@的区别

  • $*得到所有参数的字符串形式
  • $@得到所有参数的数组形式,可以直接遍历

2. 获取一条命令的执行结果

用 ` 将一条命令包裹起来

` 这个符号,在键盘上的位置是在esc键的下方

ret=${pwd}
echo ${ret}

在 ` 包裹起来的命令中,也可以访问到变量

path='/'
ret=`ls -l ${path}`
echo ${ret}

以$(command)这种方式执行命令

ret=$(pwd)
echo ${ret}

用$(command)这种方式也可以访问到变量

path='/'
ret=$(ls -l ${path})
echo ${ret}

上面的例子中,如果想打印命令结果中的换行符,则:

path='/'
ret=$(ls -l ${path})
echo "${ret}"

$(command)方式来执行命令更加直观,但是要注意,$() 仅在 bash shell 中有效,而反引号可在多种 shell 中都可使用

3. 字符串

shell有三种方式可以表示字符串

字符串的表示

(1)变量名后直接跟上字符

str=hello
echo ${str}

输出:

hello

这种方式的字符串遇到空格,$等分隔符就会被终止

(2)单引号

str=hello
echo '${str}'

输出:

${str}

单引号里的内容是字符串原始的样子,不存在转义

(3)双引号

str=shell
echo "${str}:\"hello wolrd\""

输出:

shell:"hello world"

双引号中可以访问变量和转义

字符串的长度

str="hello"
echo ${#str}

字符串拼接

两个变量放在一起访问就可以拼接

a='hello'
b='world'
c=${a}${b}
echo ${c}

输出:

helloworld

字符串截取

(1) 从左边开始截取字符串,格式:${string: start :length},length可省略,省略时,是截取到字符串末尾

msg="hello world"
echo ${msg: 6: 5}

输出:

world

(2) 在指定位置截取字符

  • 截取chars后面的字符:${string#*chars}

其中,string 表示要截取的字符,chars 是指定的字符(或者子字符串),是通配符的一种,表示任意长度的字符串。chars连起来使用的意思是:忽略左边的所有字符,直到遇见 chars(chars 不会被截取)。

  • 截取最后一次出现chars的位置后面的内容:${string##*chars}

  • 使用 % 截取左边字符
    使用%号可以截取指定字符(或者子字符串)左边的所有字符,具体格式如下:
    ${string%chars*}

请注意 * 的位置,因为要截取 chars 左边的字符,而忽略 chars 右边的字符,所以 * 应该位于chars的右侧。其他方面%和#的用法相同

4. 运算符和流程控制

基本运算

运算符 作用
+ 加(需要结合expr命令使用)
- 减(需要结合expr命令使用)
* 乘(需要结合expr命令使用)
/ 除(需要结合expr命令使用)
% 求余(需要结合expr命令使用)
= 赋值
== 判断数值是否相等,需要结合[]使用
!= 判断数值是否不相等,需要结合[]使用
a=8
b=4
echo "a=$a,b=$b"
var=`expr ${a} + ${b}`
echo "加法结果:${var}"
var=`expr ${a} - ${b}`
echo "减法结果:${var}"
# 注意:乘号需要转义
var=`expr ${a} \* ${b}`
echo "乘法结果:${var}"
var=`expr ${a} / ${b}`
echo "除法结果:${var}"
var=`expr ${a} % ${b}`
echo "求余结果:${var}"
var=$[${a} == ${b}]
echo "是否相等:${var}"
var=$[${a} != ${b}]
echo "是否不相等:${var}"

输出:

a=8,b=4
加法结果:12
减法结果:4
乘法结果:32
除法结果:2
求余结果:0
是否相等:0
是否不相等:1

上面的例子中,调用expr命令和使用[],得到表达式的值,并将它们输出

请注意表达式两边的空格,shell中表达式两边要有空格

关系运算

运算符 作用
-eq 全称:equal,判断两个数是否相等
-ne 全称:not equal,判断两个数是否不相等
-gt 全称:greater than,判断前面那个数是否大于后面那个数
-lt 全称:less than,判断前面那个数是否小于后面那个数
-ge 全称:greater equal,判断前面那个数是否大于等于后面那个数
-le 全称:less than,判断前面那个数是否小于等于后面那个数

布尔运算

运算符 作用
! 非运算
-o 或运算
-a 并运算

逻辑运算

运算符 作用
&& 逻辑并
| 逻辑或

文件判断

运算符 作用
-e 判断对象是否存在
-d 判断对象是否存在,并且为目录
-f 判断对象是否存在,并且为常规文件
-l 判断对象是否存在,并且为符号链接
-h 判断对象是否存在,并且为软链接
-s 判断对象是否存在,并且长度不为0
-r 判断对象是否存在,并且可读
-w 判断对象是否存在,并且可写
-x 判断对象是否存在,并且可执行
-o 判断对象是否存在,并且属于当前用户
-g 判断对象是否存在,并且属于当前用户组
-nt 判断file1是否比file2新
-ot 判断file1是否比file2旧

流程控制语句

(1) if语句

if语句格式如下:

if [ <condition> ]
then
    #do something
elif [ <condition> ]
then
    #do something
else
    #do something
fi

如果想把then和if放同一行

if [ <condition> ] ; then
    #do something
elif [ <condition> ] ; then
    #do something
else
    #do something
fi

其中elif和else可以省略

例子:

read file

if [ -f ${file} ] ; then
echo 'this is normal file.'
elif [ -d ${file} ] ; then
echo 'this is dir'
elif [ -c ${file} -o -b ${file} ] ; then
echo 'this is device file.'
else
echo 'this is unknown file.'
fi

逻辑判断也可以用test命令,它和[]的作用是一样的

a=4
b=4
if test $[a+2] -eq $[b+2]
then
   echo "表达式结果相等"
else
   echo "表达式结果不相等"
fi

输出:

表达式结果不相等

(2) for 语句

if语句格式如下:

for [ <var> ] in [list] 
do
# do something
done

例子:

read input
for val in ${input} ; do
echo "val:${val}"
done

输入:

1 2 3 4 5

输出:

val:1

val:2

val:3

val:4

val:5

(3) while 语句

while [ <condition> ]
do
    #do something
done

例子:

a=1
sum=0
while [ ${a} -le 100 ] ;do
sum=`expr ${sum} + ${a}`
a=`expr ${a} + 1`
done

echo ${sum}

输出:

5050

5. 函数

  1. 用function关键字来定义一个函数
  2. 直接写一个函数名来调用一个无参数的函数
  3. 函数有参数,调用时,在函数名后面写上参数,多个参数用空格隔开
  4. 调用函数时传递参数,在函数体内部,通过 $n的形式来获取参数的值,例如:$1表示第1个参数,$2表示第2个参数...

函数的结构

function foo(){
# do everything...
}

函数的用法示例

function foo(){
    local name=$1
    local age=$2
    echo "my name is: ${name},i'm ${age} years old."
}
foo "luoye" 26

输出:

my name is: luoye,i'm 26 years old.

6. 参考

http://c.biancheng.net/shell/
http://www.runoob.com/linux/linux-shell-process-control.html
https://www.cnblogs.com/qlqwjy/p/8684630.html