Shell 脚本入门 ②

目录

4. 流程控制

4.1. if 语句

4.2. case 语句

4.3. while 语句

4.4. until 循环

4.5. for 循环

4.6. 无限循环

4.7. 退出循环

5. 输入、输出重定向

5.1. 命令列表

5.2. /dev/null 文件

5.3. Here 文档

6. 函数

6.1. 基本语法

6.2. 函数参数

7. 包含文件(封装函数库)

8. 常用命令

8.1. find 命令

8.2. echo 命令

8.3. printf 命令

8.4. test 命令

9. 补充

9.1. 变量替换

9.2. 有类型变量

9.3. 使用 bc 进行浮点数运算

9.4. [ ... ] 与 [[ ... ]]

4. 流程控制

4.1. if 语句

  • 大多使用关系运算符检查关系
# 语法格式
if condition1
then
    command1
    ...
elif condition2
then
    command2
else
    commandN
fi

4.2. case 语句

# 语法格式
case 值 in
    模式1)
        command1
        command2
        ...
        commandN
        ;;
    模式2)
        command1
        command2
        ...
        commandN
        ;;
    *)
        commandDefault
        ;;
esac

4.3. while 语句

  • 用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:
# 语法格式
while condition
do
    command
done

4.4. until 循环

  • 执行一系列命令直至条件为 true 时停止,它与 while 循环 在处理方式上刚好相反。
# 语法格式
until condition
do
    command
done

4.5. for 循环

# 语法格式
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

4.6. 无限循环

# 语法1
while :
do
    command
done

# 语法2
while true
do
    command
done

# 语法3
for (( ; ; ))

4.7. 退出循环

  • break 跳出整个循环,执行循环体后面的代码,支持 break n 退出多层嵌套循环
  • continue 结束当前循环,同样支持 continue n 退出多层

5. 输入、输出重定向

5.1. 命令列表

命令

说明

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),Unix程序默认从 stdin 读取数据。
    • 1 标准输出(STDOUT),Unix程序默认向 stdout 输出数据。
    • 2 标准错误输出(STDERR),Unix程序会向 stderr 流中写入错误信息。
  • 示例:
# 将 stdout 和 stderr 合并后重定向到 file
➜  command > file 2>&1

5.2. /dev/null 文件

  • 这是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,也什么也读不到。我们通常将命令的输出重定向到它,起到“禁止输出”的效果。
# 屏蔽 stdout 和 stderr
➜  command > /dev/null 2>&1

5.3. Here 文档

# 将两个 delimiter 之间的内容(document) 作为输入传递给 command。
command << delimiter
document
delimiter

说明:

  • 结尾的 delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
  • 开始的 delimiter 前后的空格会被忽略掉。

6. 函数

6.1. 基本语法

[ function ] funcName [()] {

    command;

    [return int;]

}

说明:

  • function 关键字非必须;
  • 如果该函数不传入变量,这函数名的后面的括号可以不加;
  • return函数返回值
    • 非必须,默认返回最后一条命令的执行结果;
    • 它只能返回 1 ~ 255 之间的整数,通常只是用来供其它地方获取状态,比如 0 成功,1 或 非 0 失败;
    • 也可以使用 echo 输出一个字符串作为函数的返回值。
  • 调用函数仅使用其函数名,如 funcName;
  • 所有函数在使用前必须定义,即函数调用必须要在函数声明之后。

6.2. 函数参数

func() {
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    ...
    echo "第十个参数为 ${10} !"
    ...
}

# 调用并传参
func param1 param2 param3

说明:

  • 在函数体内部,通过 $n 的形式来获取参数的值,例如:$1 表示第一个参数,$2 表示第二个参数;
  • 当 n >= 10 时,需要使用 ${n} 来获取参数。

7. 包含文件(封装函数库)

通常我们将公用的函数抽离到单独文件,以便重复调用,减少冗余代码。

对于一个函数库文件:

  • 后缀名任意,通常使用 .lib 进行标识;
  • 一般不授予可执行权限;
  • 不需要跟脚本放在同一级目录,只需在脚本引用时指定;
  • 通常第一行一般使用 #!/bin/echo 输出警告信息,避免用户执行。

示例:

#!/bin/echo
# /home/user1/lib/comm_function.lib

function add {
    echo "`expr $1 + $2`"
}
#!/bin/bash
# /home/user1/test.sh

# 引入函数库文件
# 使用绝对 或 相对路径
. ./lib/comm_function.lib

# 使用文件中的函数
add 1 3
➜  sh -x test_functions.sh
+ . ./lib/comm_function.lib
+ add 1 3
++ expr 1 + 3
+ echo 4
4

8. 常用命令

8.1. find 命令

语法:find [路径] [选项] [操作]

选项

选项

说明

选项

说明

-name

文件名

-iname

文件名(忽略大小写)

-perm 777

文件权限

-type f|d|l|c|b|p

文件类型

-user

文件属主

-nouser

无有效属主

-group

文件属组

-nogroup

无有效属组

-size -n|+n

文件大小

-prune

排除某些查找目录(通常与 -path 一同使用)

-mindepth n

从 n 级子目录开始查找

-maxdepth n

最多搜索到 n 级子目录

-mtime -n|+n

文件修改时间(天)

-mmin -n|+n

文件修改时间(分钟)

-newer file1

文件修改时间比 file1 早

示例:

# 文件名
➜  find /etc/ -name '*.conf'

# 文件类型
# f 文件;d 目录;c 字符设备文件;
# b 块设备文件;l 链接文件;p 管道文件
➜  find /etc/ -type f

# 文件大小
# -n 小于等于;+n 大于等于
➜  find . -size +100M
➜  find . -size -10k

# 文件修改时间
# -n < n天以内修改过的文件;
# n = n 天修改过得文件;
# +n > n天以外修改过的文件;
➜  find . -mtime -3
➜  find . -mtime 3
➜  find . -mtime +3

# 排除目录
# -path ./test1 -prune 排除 test1 目录
# -path ./test2 -prune 排除 test2 目录
# -o type f 固定结尾写法
➜  find . -path ./test1 -prune -o -path ./test2 -prune -o type f

操作

  • -print 打印输出
  • -exec 'command' {} \;  其中 {} 是前面查找匹配到的结果
  • -ok 与 exec 功能一样,但每次操作都给用户提示,由用户决定是否执行对应的操作。

示例:

# 查找 30 天以前的日志文件并删除
➜  find /var/log -name '*.log' -mtime +30 -exec rm -f {} \;

# 查找所有 .conf 文件,并移动到指定目录
➜  find /etc/apache -name '*.conf' -exec cp {} /home/user1/backup \;

8.2. echo 命令

用于字符串的输出,基本格式 echo string。

使用示例:

# 显示普通字符
➜  echo "It is a test" # 输出 It is a test

# 显示转义字符
➜  echo "\"It is a test\"" # 输出 "It is a test"

# 显示变量
#!/bin/sh
NAME="xiaoming"
➜  echo "$NAME is a test" # 输出 xiaoming is a test

# 显示换行
➜  echo -e "OK! \n" # -e 开启转义
➜  echo "It is a test"

# 显示不换行
➜  echo -e "OK! \c" # -e 开启转义 \c 不换行
➜  echo "It is a test"

# 显示结果定向至文件
➜  echo "It is a test" > myfile

# 显示命令执行结果
➜  echo `date`

8.3. printf 命令

模仿 C 程序库(library)里的 printf() 程序,主要用于格式化输出。

默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n。

其基本语法格式为:

➜  printf  format-string  [arguments...]

说明:

  • format-string 为格式控制字符串
  • arguments 为参数列表。

示例:

➜  printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
➜  printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
➜  printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
➜  printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
姓名     性别   体重kg
郭靖     男      66.12
杨过     男      48.65
郭芙     女      47.99

其中:

  • %s %c %d %f 都是格式替代符;
  • %-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
  • %-4.2f 指格式化为小数,其中.2指保留2位小数。

更多使用示例:

# 没有引号也可以输出
➜  printf %s abcdef

# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
➜  printf %s abc def
abcdef

➜  printf "%s\n" abc def
abc
def

# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
➜  printf "%s and %d \n"
 and 0

8.4. test 命令

用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试(详见第3节对应的运算符部分)。

基本使用示例:

cd /bin
if test -e ./bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

9. 补充

9.1. 变量替换

规则

说明

示例var="Hello shell"

${变量#匹配规则}

从头开始匹配,最短删除

${var#*e} => llo shell

${变量##匹配规则}

从头开始匹配,最长删除

${var##*e} => ll

${变量%匹配规则}

从尾开始匹配,最短删除

${var%e*} => Hello sh

${变量%%匹配规则}

从尾开始匹配,最长删除

${var%%e*} => H

${变量/旧字符串/新字符串}

只替换匹配到的第一个

${var/e/*} => H*llo shell

${变量//旧字符串/新字符串}

全部替换

${var//e/*} => H*llo sh*ll

9.2. 有类型变量

shell 中变量默认都是字符串,除非使用以下方式声明。

declare 或 typeset 参数

说明

-r

只读

-i

整数

-a

数组

-f

在脚本中显示定义的函数和内容

-F

在脚本中显示定义的函数

-X

将变量声明为环境变量

示例:

➜  declare -r var1="hello shell type"
➜  var1="hello lalala"
zsh: read-only variable: var1

9.3. 使用 bc 进行浮点数运算

系统内置,支持 +、-、*、/、^ 指数、% 取余,并使用 scale 指定小数位数,默认 0。

示例:

➜  which bc
/usr/bin/bc

# 示例
➜  echo "5+4" | bc
9
➜  echo "5-4" | bc
1
➜  echo "5*4" | bc
20
➜  echo "5/4" | bc
1
➜  echo "scale=3;5/4" | bc
1.250
➜  echo "5%4" | bc
1
➜  echo "5^4" | bc
625

9.4. [ ... ] 与 [[ ... ]]

  • [[ 是关键字,许多 shell 并不支持这种方式。
    • 所有的字符都不会被文件扩展或是标记分割,但是会有参数引用和命令替换;
    • 更能防止脚本里的许多逻辑错误,比如说 &&, ||, < 和 > 操作符能在一个 [[ ... ]] 测试里通过,但在 [ ... ] 结构会发生错误。
    • 会进行算术扩展。
  • [ 是一条命令,与 test 等价,大多数的 shell 都支持。
    • 在其中的表达式应是它的命令行参数,所以串比较操作符 > 与 < 必须转义,否则就变成 IO 重定向操作符了。
    • 不会进行算术扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值