shell学习记录
Star Sea

shell 常用于服务器上编译部署脚本、文件归档等场景。此文记录常用的语法,方便后续使用查找。

变量

常用系统变量

$HOME、 $PWD、 $SHELL、 $USER 等

特殊变量

  • $n

n 为数字, $0 代表该脚本名称, $1-$9 代表第一到第九个参数, 十以上的参数, 十以上的参数需要用大括号包含, 如${10}

  • $#

获取所有输入参数个数, 常用于循环,判断参数的个数是否正确以及加强脚本的健壮性

  • $*、 $@
    代表命令行中所有的参数,$*把所有的参数看成一个整体 ,$@把每个参数区分对待
  • $?

最后一次执行的命令的返回状态。 如果这个变量的值为 0, 证明上一个命令正确执行; 如果这个变量的值为非 0(具体是哪个数, 由命令自己来决定) , 则证明上一个命令执行不正确

字符串处理

  • 获取字符串长度

${#string} 获取字符串string的长度
${string:1:4} 截取字符串,从第2个字符开始,截取长度为4

  • 查找字符串

查找字符 i 或 o 的位置(哪个字母先出现就计算哪个)

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

数组

数组的定义用小括号包裹,数组的值之间用空格区隔

1
2
3
4
5
6
array_name=(value0 value1 value2 value3)

# 单独定义也可以
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
数组的读取

${array_name[n]} 获取数组的某一项
${array_name[@]} 获取数组所有参数
${#array_name[@]}、${#array_name[*]} 获取数组元素的个数

运算符

$((运算式)) 或 $[运算式]

关系运算符

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

布尔运算符

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

逻辑运算符

&& 逻辑的 AND
|| 逻辑的 OR

字符串运算符

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

文件测试运算符

-b file 检测文件是否是块设备文件,如果是,则返回 true。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。
-d file 检测文件是否是目录,如果是,则返回 true。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。
-p file 检测文件是否是有名管道,如果是,则返回 true。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。
-r file 检测文件是否可读,如果是,则返回 true。
-w file 检测文件是否可写,如果是,则返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。

流程控制

if判断

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 单分支
if [ 条件判断式 ];then
程序
fi

if [ 条件判断式 ]
then
程序
fi

# 多分支
if [ 条件判断式 ]
then
程序
elif [ 条件判断式 ]
then
程序
else
程序
fi

举个栗子

1
2
3
4
5
6
7
8
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "banzhang zhen shuai"
elif [ $1 -eq 2 ]
then
echo "cls zhen mei"
fi

case语法

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
case $变量名 in
"值 1"
如果变量的值等于值 1, 则执行程序 1
;;
"值 2"
如果变量的值等于值 2, 则执行程序 2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值, 则执行此程序
;;
esac

注意事项:
(1) case 行尾必须为单词“in” , 每一个模式匹配必须以右括号“) ” 结束。
(2) 双分号“;;” 表示命令序列结束, 相当于 java 中的 break。
(3) 最后的“*) ” 表示默认模式, 相当于 java 中的 default。

for循环

基本语法

1
2
3
4
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done

举个栗子

1
2
3
4
5
6
7
#!/bin/bash
sum=0
for((i=0;i<=100;i++))
do
sum=$[$sum+$i]
done
echo $sum

for…in语法

1
2
3
4
for 变量 in 值 1 值 2 值 3…
do
程序
done

举个栗子

1
2
3
4
5
6
7
#!/bin/bash
#打印数字

for i in cls mly wls
do
echo "ban zhang love $i"
done

while循环

基本语法

1
2
3
4
while [ 条件判断式 ]
do
程序
done

举个栗子

1
2
3
4
5
6
7
8
9
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
sum=$[$sum+$i]
i=$[$i+1]
done
echo $sum

读取控制台输入

  1. 基本语法

read (选项) (参数)
①选项:
-p: 指定读取值时的提示符;
-t: 指定读取值时等待的时间(秒) 如果-t 不加表示一直等待
②参数
变量: 指定读取值的变量名

  1. 举个栗子
    1
    2
    3
    4
    #!/bin/bash

    read -t 7 -p "Enter your name in 7 seconds :" NN
    echo $NN

函数

系统函数

basename

  1. 基本语法

basename [string / pathname] [suffix] ( 功能描述: basename 命令会删掉所有的前缀包括最后一个(‘/’) 字符, 然后将字符串显示出来。
basename 可以理解为取路径里的文件名称
选项:
suffix 为后缀, 如果 suffix 被指定了, basename 会将 pathname 或 string 中的 suffix 去掉

  1. 举个栗子

    1
    2
    3
    # 以下可以取出banzhang

    basename /home/lazy5/banzhang.txt .txt

    dirname

  2. 基本语法

dirname 文件绝对路径 (功能描述: 从给定的包含绝对路径的文件名中去除文件名(非目录的部分) , 然后返回剩下的路径(目录的部分) )
dirname 可以理解为取文件路径的绝对路径名称

  1. 举个栗子

    1
    2
    3
    # /home/lazy5

    dirname /home/lazy5/banzhang.txt

    自定义函数

  2. 基本语法

    1
    2
    3
    4
    5
    [ function ] funname[()]
    {
    Action;
    [return int;]
    }
  3. 说明

(1) 必须在调用函数地方之前, 先声明函数, shell 脚本是逐行运行。 不会像其它语言一
样先编译。
(2) 函数返回值, 只能通过$?系统变量获得, 可以显示加: return 返回, 如果不加, 将
以最后一条命令运行结果, 作为返回值。 return 后跟数值 n(0-255)

  1. 举个栗子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/bash
    function sum()
    {
    s=0
    s=$[$1+$2]
    echo "$s"
    }
    read -p "Please input the number1: " n1;
    read -p "Please input the number2: " n2;
    sum $n1 $n2;

    文件包含

  2. 基本语法

    1
    2
    3
    4
    5
    . filename   # 注意点号(.)和文件名中间有一空格



    source filename
  3. 举个栗子

test1.sh 代码如下:

1
2
3
#!/bin/bash

url="http://www.starsea.club"

test2.sh 代码如下:

1
2
3
4
5
6
7
8
9
#!/bin/bash

#使用 . 号来引用test1.sh 文件
. ./test1.sh

# 或者使用以下包含文件代码
# source ./test1.sh

echo "我的地址:$url"

输入/输出重定向

命令 说明
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 之间的内容作为输入。

需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)

输出重定向

  1. 基本语法

    1
    command1 > file1
  2. 举个栗子

    1
    2
    3
    4
    5
    6
    7
    8
    # 将who命令的结果输出到文件users
    who > users

    # 替换users的内容
    echo "替换内容" > users

    # 追加内容到users
    echo "追加内容" >> users

输入重定向

  1. 基本语法

    1
    command1 < file1
  2. 举个栗子

    1
    2
    3
    4
    5
    # 会输出2 users,行数+文件名
    wc -l users

    # 此处直接输出2,只显示行数,因为wc只知道是从标准输入读取的内容
    wc -l < users

同时输出/输入

1
command1 < infile > outfile

command1 < infile > outfile

重定向深入讲解

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
如果希望 stderr 重定向到 file,可以这样写:

1
2
3
4
command 2>file

# stderr追加
command 2>>file

如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:

1
2
3
4
5
command > file 2>&1

或者

command >> file 2>&1

如果希望对 stdin 和 stdout 都重定向,可以这样写:

1
command < file1 >file2

/dev/null 文件

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

1
command > /dev/null

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

1
command > /dev/null 2>&1