bash浅入

Bash(GNU Bourne-Again Shell)是一个为GNU计划编写的Unix shell,它是许多Linux平台默认使用的shell。

shell是一个命令解释器,是介于操作系统内核与用户之间的一个绝缘层。准确地说,它也是能力很强的计算机语言,被称为解释性语言或脚本语言。它可以通过将系统调用、公共程序、工具和编译过的二进制程序”粘合“在一起来建立应用,这是大多数脚本语言的共同特征,所以有时候脚本语言又叫做“胶水语言”

而我认为shell和bash的区别,bash就像是shell的一个子集,bash是目前比较常用的一种shell脚本,可移植性强,大多数情况说的shell 指的就是bash。


shell脚本规范

#!/bin/bash
# This is a comment
echo Hello World
  • #!/bin/bash这一行是表示使用 /bin/bash 作为脚本的解释器,这行要放在脚本的行首并且不要省略。

  • #!说明这个文件的类型,有点类似于 Windows 系统下用不同文件后缀来表示不同文件类型。

  • Linux 系统根据#!及该字符串后面的信息确定该文件的类型。在 BASH 中 第一行的#!及后面的 /bin/bash 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。BASH 这个程序一般是存放在 /bin 目录下,如果你的 Linux 系统比较特别,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 这样的目录下

  • #号开头的行都是注释语句

运行Bash脚本的方式:

# 使用shell来执行
$ sh 文件名.sh

# 使用bash来执行
$ bash 文件名.sh

# 使用.来执行
$ . ./文件名.sh

# 使用source来执行
$ source 文件名.sh

# 还可以赋予脚本所有者执行权限,允许该用户执行该脚本
$ chmod u+rx hello.sh
$  ./文件名.sh



bash字符

 - 注释(#)

 - 命令分隔符(;)
   使用分号(;)可以在同一行上写两个或两个以上的命令。

 - 终止case选项(;;)

 - 等价于 source 命令(.)
   bash 中的 source 命令用于在当前 bash 环境下读取并执行 FileName.sh 中的命令,即“. FileName.sh”命令等价于“source FileName.sh”

 - 双引号(")和单引号(')
   单引号会直接认为是字符,而双引号会被认为是一个变量

 - 文件名路径分隔符(/)

 - 转义字符(\)
   \也提供续行功能,也就是在一行里编写多行命令的功能。\n 表示新的一行, \r 表示回车

 - 命令优先执行(`)
   反引号中的命令会优先执行,如cp `mkdir back` test.sh back,先创建了 back 目录,然后复制 test.sh 到 back 目录

 - 空命令(:)
   等价于“NOP”(no op,一个什么也不干的命令)

 - 变量($)

 - 命令组和初始化数组(( ))
   在括号中的命令列表,将会作为一个子 shell 来运行。在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量,也就是在子shell 中创建的变量。
   如a=123;( a=321; );echo "$a",执行后a的值为123而不是321,,因为括号将判断为局部变量,脚本本身,不能够读取在子进程中创建的变量,也就是在子shell 中创建的变量
   如arr=(1 4 5 7 9 21) \echo ${arr[3]} # get a value of arr

 - 代码块({ })
   又被称为内部组,这个结构事实上创建了一个匿名函数(一个没有名字的函数)。然而,与“标准”函数不同的是,在其中声明的变量,对于脚本其他部分的代码来说还是可见的。如a=123;{ a=321; };echo "a = $a"

 - 条件表达式和引用数组元素([ ])

 - 重定向(< 和 >)
   test.sh > filename:重定向test.sh的输出到文件 filename 中。如果 filename 存在的话,那么将会被覆盖。
   test.sh &> filename:重定向 test.sh 的 stdout(标准输出)和 stderr(标准错误)到 filename 中。
   test.sh >&2:重定向 test.sh 的 stdout 到 stderr 中。
   test.sh >> filename:把 test.sh 的输出追加到文件 filename 中。如果filename 不存在的话,将会被创建。

 - 管道(|)
   分析前边命令的输出,并将输出作为后边命令的输入。这是一种产生命令链的好方法。如ls -l | tr 'a-z' 'A-Z',将当前目录的详细信息全部用大写来输出

 - 选项参数(-)
   在所有的命令内如果想使用选项参数的话,前边都要加上“-”

 - 表示 home 目录(~)



变量

变量的名字就是变量保存值的地方。引用变量的值就叫做变量替换。如果 variable 是一个变量的名字,那么 $variable 就是引用这个变量的值,即这变量所包含的数据。

定义变量时,变量名不加美元符号,如: myname=“shiyanlou”。注意:变量名和等号之间不能有空格。同时,变量名的命名须遵循如下规则:

  • 首个字符必须为字母(a-z,A-Z)。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

使用变量:变量名前加美元符号,如:echo $myname;echo ${myname},推荐给所有变量加花括号,加花括号帮助解释器识别变量的边界

只读变量:使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。如readonly variableName

局部变量:这种变量只有在代码块或者函数中才可见。

环境变量:这种变量将影响用户接口和 shell 的行为。在通常情况下,每个进程都有自己的“环境”,这个环境是由一组变量组成的,这些变量中存有进程可能需要引用的信息。在这种情况下,shell 与一个一般的进程没什么区别。


运算符


算数运算符

运算符 说明
+ 加法
- 减法
* 乘法
/ 除法
% 取余
= 赋值
== 相等, 用于比较两个数字,相同则返回 true
!= 不相等,用于比较两个数字,不相同则返回true

如下例:

#!/bin/bash
a=10
b=20
val=`expr $a \* $b`
echo "a * b : $val"

在这里插入图片描述

  • 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
  • expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
  • 注意使用的反引号(esc键下边)
  • 表达式和运算符之间要有空格$a + $b写成$a+$b不行
  • 条件表达式要放在方括号之间,并且要有空格[ $a == $b ]写成[$a==$b]不行
  • 乘号(*)前边必须加反斜杠(\)才能实现乘法运算

关系运算符

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

关系运算符只支持数字,不支持字符串


逻辑运算符

运算符 说明
&& 逻辑的AND
|| 逻辑的OR

字符串运算符

运算符 说明
= 检测两个字符串是否相等,相等返回true
!= 检测两个字符串是否不相等,不相等返回true
-z 检测字符串长度是否为0,为0返回true
-n 检测字符串长度是否不为0,不为0返回true
str 检测字符串是否为空,不为空返回true

如下例:

#!/bin/bash
a="abc"
if [ $a ]
then
   echo "$a : The string is not empty"
else
   echo "$a : The string is empty"
fi

在这里插入图片描述

文件比较运算符

运算符 说明
-e 如果文件存在返回true
-f 如果这个文件是一个一般文件(并不是目录或者设备文件),返回true
-s 如果文件大小不为零,返回true
-d 如果这是一个目录,返回true
-b 如果这是一个块设备(软盘,光驱,等等),返回true
-c 如果这是一个字符设备(键盘,modem,声卡,等等),返回true
-p 如果这个文件是一个管道,返回true
-h 如果这是一个符号链接,返回true
-L 如果这是一个符号链接,返回true
-S 如果这是一个socket,返回true
-t 文件(描述符)被关联到一个终端设备上,这个测试选项一般被用来检测脚本中的stdin([-t 0]) 或者stdout([-t 1])是否来自于一个终端
-r 文件是否具有可读权限(指的是正在运行这个命令的用户是否具有读权限)
-w 文件是否具有可写权限(指的是正在运行这个命令的用户是否具有写权限)
-x 文件是否具有可执行权限(指的是正在运行这个命令的用户是否具有可执行权很)
-g set-group-id(sgid)标记被设置到文件或目录上
-k 设置粘贴位
-O 判断你是否为文件的拥有者
-G 文件的group-id是否与你的相同
-N 从文件上一次被读取到现在为止,文件是否被修改过
f1 -nt f2 如果文件f1比文件f2新,返回true
f1 -ot f2 如果文件f1比文件f2旧,返回true
f1 -ef f2 如果文件f1和文件f2是相同文件的硬链接,返回true
! 非, 反转上边所有测试的结果(如果没给出条件,那么返回true)

如下例:

#!/bin/bash

file="/test.sh"
# 由于没有给出条件,所以返回true
if [ ! ]
then
   echo "File exists"
else
   echo "File not exists"
fi



流程控制


if else

语法格式:

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

for 循环

语法格式:

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

如下例:

#!/bin/bash
for str in This is a string
do
    echo $str
done

在这里插入图片描述

# 无限循环语法格式:
for (( ; ; ))

while 语句

while循环用于不断执行一系列命令,也用于从输入文件中读取数据

语法格式:

while condition
do
    command
done

如下例:

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

在这里插入图片描述
while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量MAN,按结束循环。

如下例:

#!/bin/bash
echo 'press <CTRL-D> exit'
echo -n 'Who do you think is the most handsome: '
while read MAN
do
    echo "Yes!$MAN is really handsome"
done

在这里插入图片描述

# 无限循环语法格式:
while :
do
    command
done


或者
while true
do
    command
done

until 循环

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

条件可为任意条件,判断发生在循环末尾,因此循环至少执行一次。

语法格式:

until condition
do
    command
done

如下例:

#!/bin/bash
int=1
until (( $int>1 ))
do
    echo $int
    let "int++"
done

在这里插入图片描述

case 语句

多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

语法格式:

casein
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac
  • 取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;,两个分号在这里表示break。
  • 取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 *捕获该值,再执行后面的命令。

如下例:

#!/bin/bash
echo 'Enter a number between 1 and 4:'
echo 'The number you entered is:'
read aNum
case $aNum in
    1)  echo 'You have chosen 1'
    ;;
    2)  echo 'You have chosen 2'
    ;;
    3)  echo 'You have chosen 3'
    ;;
    4)  echo 'You have chosen 4'
    ;;
    *)  echo 'You did not enter a number between 1 and 4'
    ;;
esac

在这里插入图片描述

break 命令

break命令允许跳出所有循环(终止执行后面的所有循环)

如下例:

#!/bin/bash
while :
do
    echo -n "Enter a number between 1 and 5:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "The number you entered is $aNum!"
        ;;
        *) echo "The number you entered is not between 1 and 5!"
            break
        ;;
    esac
done

在这里插入图片描述

continue 命令

仅仅跳出当前循环

如下例:

#!/bin/bash
while :
do
    echo -n "Enter a number between 1 and 5: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "The number you entered is $aNum!"
        ;;
        *) echo "The number you entered is not between 1 and 5!"
            continue
            echo "game over"
        ;;
    esac
done



函数

语法格式:

[ function ] funname [()]

{

    action;

    [return int;]

}
  • 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
  • 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
  • 调用函数时可以向其传递参数。在函数体内部,通过 n 的形式来获取参数的值,例如$1表示第一个参数,$2表示第二个参数… 当n>=10时,需要使用${n}来获取参数。
  • 函数返回值在调用该函数后通过 $?来获得
  • 所有函数在使用前必须定义

如下例:

#!/bin/bash

demoFun(){
    a=266
    echo "The first parameter is $1 !"
    echo "The second parameter is $2 !"
    echo "The tenth parameter is ${10} !"
    echo "The eleventh parameter is ${11} !"
    echo "The total number of parameters is $# !"
    echo "Outputs all parameters as a string $* !"
    return $(($a))
}
demoFun 1 2 3 4 5 6 7 8 9 34 73
echo "返回值为:$?"

在这里插入图片描述
为何最后红框内的数值出现异常呢?原因就是shell的函数规定了return后跟的数值范围在0-255


参考

https://www.shiyanlou.com/courses/944

发布了22 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42403866/article/details/104321949
今日推荐