shell脚本知识记录

2022-08-08 08:19:44 浏览数 (1)

先来简单的看一下变量定义的规则

在Shell中,使用变量之前不需要事先声明,只是通过使用它们来创建它们;

在默认情况下,所有变量都被看做是字符串,并以字符串来存储;

Shell变量是区分大小写的;

在赋值变量的时候等号两端不能有空格-_-

定义了变量之后,一定要加上$符号才能使用

#! /bin/bash

VAR1=HELLO

VAR2=MY NAME

VAR3="MY AGE"

VAR4 = IS

echo VAR1 #error 能输出 但不是输出该变量

echo $VAR1 #ok 正常读取变量并打印

echo $VAR2 #error 定义变量的值 用空格隔开了

echo $VAR3 #ok 作为一整个字符串

echo $VAR4 #error 变量定义的时候等号两端有空格

输出的结果为

./test.sh: line 2: NAME: command not found

./test.sh: line 4: VAR4: command not found

VAR1

HELLO

MY AGE

关于shell脚本的执行:shell基本一般是以.sh为后缀,然后在*unix系统下一般都是直接使用./[当前shell文件名] 的方式来执行,也可以使用全部经/[shell文件名]的方式来执行,并且需要注意的是 被执行的shell文件一定是有含有可执行权限了的,可以使用chmod命令来修改

还有另一个点就是在调用变量的时候 ,如果在双引号中直接使用$name任然可以识别,但是如果在单引号是就无法适用$name的方式来调用变量

read读取输入值

这个功能就像java中的readline来读取,使用方法为

#! /bin/bash

echo "whats your name?"

read NAME  #在这里读取输入值到NAME变量中 ,这里如果不输入会停留在屏幕上

echo "webcome back" $NAME

exit 0

可以看到熟悉的结果为

whats your name?

tom

webcome back tom

环境变量

Shell脚本还提供能一些实用的环境变量

1. $HOME:为当前用户所在的目录

3. $PATH:当前用户所能方法的PATH变量

4. $#:传递参数额个数 类似java中的args.length

5. $$:Shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件。

#! /bin/bash

echo "当前用户所在的目录为" $HOME

echo "当前的执行目录为" $(pwd)  #这个是访问当前的脚本的目录很实用

echo "当前用户所能访问的PATH为" $PATH

echo "当前参数的参数个数为" $#  #这儿参数的格式是使用空格隔开的哦

echo "当前Shell脚本的进程号为" $$

exit 0

可以到看的结果是

yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  hello world

当前用户所在的目录为 /Users/yanyl

当前的执行目录为 /Users/yanyl/Downloads

当前用户所能访问的PATH为 /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/yanyl/Program/apache-maven-3.2.5/bin:/Users/yanyl/Program/scala-2.10.4//bin

当前参数的参数个数为 2

当前Shell脚本的进程号为 43746

参数变量

刚刚看到可以使用read关键字可以来读取输入变量,但是我们可能更加常用的是参数变量,也就是$#的个数,它的规则如下

1. $#表示参数变量的个数

2. $0表示当前的脚本名称

3. $1,$2...$n表示依次能读取到的变量 但是如果参数变量不够,$i会被赋值为空

#! /bin/bash

echo "当前输入的参数变量的长度为" $#

echo "当前执行的Shell脚本为" $0

echo "当前输入的第一个参数为" $1

echo "当前输入的第二个参数为" $2

echo "当前的输入的第三个参数为" $3 #现在如果只传2个参数 这里将不会报错

exit 0

可以看到的结果为

yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  hello world

当前输入的参数变量的长度为 2

当前执行的Shell脚本为 ./hi.sh

当前输入的第一个参数为 hello

当前输入的第二个参数为 world

当前的输入的第三个参数为

可以看到在Shell脚本中去读取参数变量还是很方便的,这样配合下面的条件判断以及循环就可以做很多事情了

读取返回码

一般的程序/命令在执行结束时都会返回一个 返回码,比如

java的system.exit(-1)

python的sys.exit(-1)

还有上面Shell脚本中的最后一行exit 0

如果你不显式指定返回码,一般默认为0,表示正常退出,但是有时候显式的指定返回码是一个好习惯哦

这些程序在Shell中执行的,可以使用$?来读取上一个程序执行下来的脚本码

#! /bin/bash

du -s #执行的返回码一般为0

echo du -s的返回码为 $?

duu -s #这个命令故意输错

echo duu -s的返回码为 $?

exit 0

可以看到正确的结果为

28494656    .

du -s的返回码为 0

./hi.sh: line 6: duu: command not found

duu -s的返回码为 127

返回码配上if判断,就可以使用shell脚本自由得在各个语言以及命令中穿梭啦^_^

数学运算

在上一小节中说道,Shell中变量一般都是当字符串来处理,那我遇到数字运算该咋办呢??

可以先看

#! /bin/bash

a=1 2

b=$a 3

echo $a

echo $b

exit 0

结果却看到

1 2

1 2 3

那在Shell中解决这个问题大概有这么几种方法

let关键字

#! /bin/bash

let a=1 2

let b=$a 3

echo $a

echo $b

exit 0

输出的结果为

3

6

这个关键词大致需要注意以下几个点:

let只支持整数运算

当let后面的运算部分有bash关键字时,需加双引号

幂次方可以使用**符号

使用(())

#! /bin/bash

((a=1 2))

((b=$a 3))

echo $a

echo $b

exit 0

结果还是正确的

3

6

(())的用法与let完全相同

使用$[]

上面的效果需要这么写

a=$[1 2]

b=$[$a 3]

其余与上面两种限制大致相同

使用expr

关于这个方式是这么写的

a=`expr 1 2`

b=`expr $a * 3`  #需要转义

需要额外注意的有:

运算符两端需要加空格 一定要记住。。。很容易失误

对于|、&、<、<=、>=、>、*运算符号需要加上</code>进行转义

使用bc

这个终于是可以用于浮点数的运算了

#! /bin/bash

a=3.1415926

b=`echo "$a*2"|bc`

echo $a

echo $b

exit 0

可以看到结果

3.1415926

6.2831852

据说这里还有一个scale来设置精度,但是我设置了感觉木有效果-_-

条件判断

if 语法

在Shell脚本中有两种书写if判断的语法

使用test 关键字

#! /bin/bash

# if test expression1 operation expression2

if test 5 -gt 4;  #这个最后的结尾可以加上:或者;

then

    echo "ok,5>4"

else

    echo "oh,no"

fi #这个结束符号必须得加

exit 0

输出为

ok,5>4

使用[和]关键字

#! /bin/bash

# if [ expression1 operation expression2 ]

if [ 5 -lt 4 ];  #注意[和]两端必须留空格 同时表达式两端都需要有空格

then

    echo "ok,5>4"

else

    echo "oh,no"

fi

exit 0

输出为

oh,no

如果还更加复杂的判断你可以使用elif继续增加条件表达式,但是别忘了加then哦

判断表达式

在Shell中有三种判断表达式

字符串比较

字符串比较 结果

string1 = string2 如果两个字符串相同,也可用==结果就为真

string1 != string2  如果两个字符串不同,结果就为真

-n string 如果字符串不为空,则结果为真

-z string 如果字符串为一个空串(null),则结果为真

这里需要注意下,-n 和 -z string比较时必须用双引号("")将变量引起来

#! /bin/bash

a=5

if [ -n "$a"  ]  #注意要空括号来包住哦

then

    echo exists

else

    echo null

fi

if [ -n "$c"  ]

then

    echo exists

else

    echo null

fi

exit 0

结果为

exists

null

算术比较

算术比较  结果

expression1 -eq expression2 如果两个表达式相等,则结果为真

expression1 -ne expression2 如果两个表达式不等,则结果为真

expression1 -gt expression2 如果expression1 大于expression2 ,则为真

expression1 -ge expression2 如果expression1 大于等于expression2 ,则为真

expression1 -lt expression2 如果expression1 小于expression2 ,则为真

expression1 -le expression2 如果expression1 小于等于expression2 ,则为真

!expression 表达式为假,则结果就为真;反之亦然

关于上面比较符号的快速记法如下:eq=equal,gt=great than,lt=less than,然后组合拼凑即可,如果觉得这样还是很难记,就可以像我一样,将这些符号记录下来,需要的时候来查表-_-

文件条件测试

文件条件测试  结果

-d file 如果文件是一个目录,则为真

-f file 如果文件是一个普通文件,则为真;也可以用来测试文件是否存在

-r file 如果文件可读,则结果为真

-s file 如果文件大小不为0,则结果为真

-w file 如果文件可写,则结果为真

-x file 如果文件可执行,则结果为真

这,真的是一个利民的测试

循环结构

for 循环

先来看一种经典C语法版的for

#! /bin/bash

for ((i=0;i<5;i ))

do

    echo $i

done

exit 0

看输出,

0

1

2

3

4

还支持在外部控制步长

#! /bin/bash

for ((i=0;i<5;))

do

    echo $i

    i=$[$i 2]

done

exit 0

0

2

4

是不是感觉基本功能都有呀,就是写某些东西写起来奇怪点

是不是有一种莫名的熟悉感

另一种就是类似foreach的情况了,他的格式是这样的

for variable in values

do

    statements

done

其中values 可能有的情况为:

使用linux命令输出的行作为迭代的输入:ls,seq,cat之类均可,其实就可以完成很强大的文件读取功能

#! /bin/bash

for i in `head -n 5 words.dit`;do  #words.dit 这是一个通用词表 每行一个词

    echo $i

done

exit 0

可以看到通用词典中前5个词

阿巴丹

阿巴岛

阿巴鸟

阿巴伊达

使用$*可以来表示遍历传入的参数列表

#! /bin/bash

for i in $*;do

    echo $i

done

exit 0

来看个结果

yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  my name is tom

my

name

is

tom

还可以使用带空格的字符串 来进行按空格分隔输出

#! /bin/bash

a="yello red green"

for i in $a;do

    echo $i

done

exit 0

这样在一定程度上可以看成一个简易的数组

这里需要注意的是包含条件以及循环逻辑是双重括号,以及开始结果的do和Done

while 循环

另一个常用的就是while循环了

他的结构是

while condition

do

    statements

done

这个也是蛮好理解的,可以来看一个demo

#! /bin/bash

echo "please ent your password:"

read pwd

while [ "$pwd"x != "root"x  ] #这里加x是为了防止啥也不输入直接回车产生的报错

do

    echo "error,please try again:"

    read pwd

done

echo "welcome here"

exit 0

看一下结果

please ent your password:

sha

error,please try again:

error,please try again:

root

welcome here

很有意思的一个哈~

until语句

这个语句与while的结构完全一样,只是使用了until关键字来代替了while,然后在条件为true的时候停止,正好与while相反

函数

Shell这么叼,能没有函数吗

[function] functon_name()

{

    statements

}

上面是定义函数的结构,大致有以下几个要点

1. 前面的function关键字可有可无,不过感觉还是加上去比较好,这样在代码里面比较好辨识

2. 函数名后面的括号中不能带参数 取的参数是用过$1,$2...$n这样的方式来取的 

3. 调用的时候直接写函数名 不需要加括号

4. 如果想传递参数的话 直接在调用后来加上参数列表 用空格隔开 (就是Shell的传参一样)

5. 使用local关键字来定义函数体里面的局部变量

7. 所以在函数调用必须在函数定义之后

先看一个小的demo

#! /bin/bash

function sayhi()

{

    echo hi $1

}

sayhi tom #前面的sayhi是函数的调用 后面的tom是传参

exit 0

可以看到输出

hi tom

函数的返回值

关于Shell的返回值方式有两种

输出给主程序,他的结构为:

function function_name()

{

    echo $something  #通过输出的方式来返回值

}

a=`function_name`  这种方式接收返回值

看到的demo可以是这样的

Press ENTER or type command to continue

#! /bin/bash

function sum()

{

    echo $[$1 $2]

}

a=`sum 1 2`

echo the sum is $a

exit 0

最终输出结果为

the sum is 3

使用return作为返回码来返回值

function function_name()

{

    return $ret #这里进行返回码的返回

}

function_name

$? #在这里接收返回值

一样再来一个demo

#! /bin/bash

function sum()

{

    return $[$1 $2]

}

sum 1 2

echo the sum is $?

exit 0

可以看到输出为

the sum is 3

case语句

这里的case的与传统的switch有点像,但是又像scala中的match模式匹配的强大,

他的结构是这样的

case variable in

    pattern [ | pattern] ...) statements;;

    pattern [ | pattern] ...) statements;;

    ...

esac

来看这个强大的demo

#! /bin/bash

function match()

{

    case $1 in

        root ) echo this is password ;;

        h* ) echo hi $1 ;; #使用通配符

        yes | YES ) echo agree with me ;; #可以进行或操作

        * ) echo everything is here;;  #你可以理解为switch中的default

    esac

}

match root

match hello

match YES

match Yes

exit 0

来看一下结果

this is password

hi hello

agree with me

everything is here

注意,这里一旦匹配中了一个之后就马上会停止匹配

外部命令/文件/语言的调用

Shell的另一个强大之处就是可以无缝的和外部的命令,文件,语言结合,去调用组织他们

1. 外部命令:一般情况下可以直接写外部命令,如果要赋值的话得使用``括起来

2. 外部文件:比如资源配置文件,profile文件之类的,可以直接使用source关键字的来执行

3. 外部语言:比如java,python可以直接使用他们的java调用jar,java文件,也可以直接使用关键字来执行python文件

总结

Shell很好很强大,得学习!!!

注意变量的字符串格式以及需要数学运算时的语法

注意变量赋值时等号两端一定不能有空格以及再取值时一定要加$

平常的控制结束符号别忘了,比如fi,doen,esac等

忘了的时候来查查这个文件

0 人点赞