Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言,用户通过这个界面访问操作系统内核的服务。而Shell 脚本(shell script),则是一种为 shell 编写的脚本程序。
$[timeformat('2019-05-29T11:55:44+08:00')]
#Linux

Shell环境

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。#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序,例如:

#!/bin/bash

运行Shell脚本有两种方法:

1.作为可执行程序:

chmod +x ./test.sh  #使脚本具有执行权限
./test.sh  #执行脚本

2.作为解释器参数

直接运行解释器,其参数就是 shell 脚本的文件名:

/bin/sh test.sh
/bin/php test.php

Shell变量

定义变量

定义变量时,变量名不加$,同时变量名要满足以下条件:

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线_。
  • 不能使用标点符号。
  • 不能使用bash里的关键字。

除了显式地直接赋值,还可以用语句给变量赋值,如:

for file in `ls /etc`
或
for file in $(ls /etc)

以上语句将 /etc 下目录的文件名循环出来。

使用变量

使用一个定义过的变量,需要在变量名前加$:

your_name="qinjx"
echo $your_name
echo ${your_name}

变量名外面的花括号是可选的,加不加都行,推荐加花括号,可以帮助解释器识别变量的边界。

只读变量

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

myUrl="http://www.google.com"
readonly myUrl
myUrl="http://www.runoob.com"
#结果如下:
/bin/sh: NAME: This variable is read only.

删除变量

变量被删除后不能再次使用。unset 命令不能删除只读变量。

unset variable_name

Shell字符串

单引号

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
str='this is a string'

双引号

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符
your_name='runoob'
str="Hello, I know you are \"$your_name\"! \n"
echo -e $str
#输出结果为:
Hello, I know you are "runoob"! 

获取字符串长度

string="abcd"
echo ${#string} #输出 4

提取子串

string="runoob is a great site"
echo ${string:1:4} # 输出 unoo

查找子串

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

Shell数组

定义数组

在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。Bash Shell 只支持一维数组(不支持多维数组)。

array_name=(value0 value1 value2 value3)

还可以单独定义数组的各个分量:

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

可以不使用连续的下标,而且下标的范围没有限制。

读取数组

读取数组元素值的一般格式是:${数组名[下标]}

使用 @ 或 * 符号可以获取数组中的所有元素:

echo ${array_name[@]}
echo ${array_name[*]}

获取数组长度

# 取得数组元素的个数
length=${#array_name[@]}
# 或
length=${#array_name[*]}

# 取得数组单个元素的长度
lengthn=${#array_name[n]}

Shell注释

以 # 开头的行就是注释,会被解释器忽略。、

或者使用一下格式多行注释:

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

Shell传参

脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数...

另外,还有几个特殊字符用来处理参数:

  • $#:传递到脚本的参数个数
  • $$:脚本运行的当前进程ID号
  • $!:后台运行的最后一个进程ID号
  • $?:显示最后命令的退出状态

Shell运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

算术运算符

例如求两数之和:

#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"

需要注意两点:

  • 表达式和运算符之间要有空格,例如2 + 2。
  • 完整的表达式要被反引号`包裹。

算术运算符如下:

  • +:加法
  • -:减法
  • *:乘法
  • /:除法
  • %:取余
  • =:赋值 a=$b 将把变量 b 的值赋给 a。
  • ==:相等。用于比较两个数字,相同则返回 true。
  • !=:不相等。用于比较两个数字,不相同则返回 true。

这里要注意乘号“”前边必须加反斜杠()才能实现乘法运算(Mac中shell的expr语法是$((表达式)),此处表达式中“”不需要转义)。

布尔运算符

布尔运算符如下:

  • !:非运算,表达式为 true 则返回 false,否则返回 true。
  • -o:或运算,有一个表达式为 true 则返回 true。
  • -a:与运算,两个表达式都为 true 才返回 true。

逻辑运算符

逻辑运算符如下:

  • &&:逻辑的 AND
  • ||:逻辑的 OR

字符串运算符

字符串运算符如下:

  • =:检测两个字符串是否相等,相等返回 true。
  • !=:检测两个字符串是否相等,不相等返回 true。
  • -z:检测字符串长度是否为0,为0返回 true。
  • -n:检测字符串长度是否为0,不为0返回 true。
  • $:检测字符串是否为空,不为空返回 true。

echo和read

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量。echo 命令用于字符串的输出。

#!/bin/sh
read name 
echo "$name It is a test"
#以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:
[root@www ~]# sh test.sh
OK                     #标准输入
OK It is a test        #输出

echo -e开启转义:

echo -e "OK! \n" # -e 开启转义
echo "It is a test"
#输出结果:
OK!

It is a test


#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
输出结果:
OK! It is a test

将结果定向至文件:

echo "It is a test" > myfile

Shell流程控制

判断

if:

if condition
then
    command1
    ...
    commandN 
fi

写成一行:

if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

if else:

if condition
then
    command1
    ...
    commandN
else
    command
fi

if elif eles:

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

循环

for:

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

写成一行:

for var in item1 item2 ... itemN; do command1; command2… done;

while:

while condition
do
    command
done

until:

until condition
do
    command
done

多选择

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

case 值 in
模式1)
    command1
    ...
    commandN
    ;;
模式2)
    command1
    ...
    commandN
    ;;
esac

case需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break。

跳出循环

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

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

Shell函数

shell中函数的定义格式如下:

[ function ] funname [()]
{
    action;
    [return int;]
}

说明:

  • 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
  • 参数返回,可以显式加return返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)。

Shell输入/输出重定向

大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。默认情况下标准输入和标准输出都是终端。

重定向命令如下:

  • command > file:将输出重定向到 file。
  • command < file:将输入重定向到 file。
  • command >> file:将输出以追加的方式重定向到 file。
  • n > file:将文件描述符为 n 的文件重定向到 file。
  • n >> file:将文件描述符为 n 的文件以追加的方式重定向到 file。
  • n >& m:将输出文件 m 和 n 合并。
  • n <& m:将输入文件 m 和 n 合并。
  • << tag:将开始标记 tag 和结束标记 tag 之间的内容作为输入。

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。

如果希望屏蔽 stdout 和 stderr,可以这样写:

$ command > /dev/null 2>&1

Shell文件包含

和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。

Shell 文件包含的语法格式如下:

. filename   # 注意点号(.)和文件名中间有一空格

或
source filename

评论