《Linux命令行大全》重点笔记4
第四部分 编写shell脚本
第24章 编写第一个shell脚本
24.1 shell脚本
-
shell脚本:就是一个包含一系列命令的文件。
-
shell:一个强大的命令行接口,也是脚本语言解释器。
24.2 编写shell脚本
三个步骤:
- 编写脚本:常用vim。
- 使脚本可执行:权限设置。
- 放在shell能发现的位置:默认shell会自动寻找某些目录找可执行文件。
1、脚本文件格式
#!:shebang,使用脚本解释器名字。
#! /bin/bash#:注释。
2、可执行权限
chmod 755 shellfile:每个人都能执行。rwx | r-x | r-x
chmod 700 shellfile:只要脚本所有者才能执行。rwx | — | —
3、脚本文件位置
两种执行方式:
- 显示指定脚本文件路径:
./shellfile当前目录下的shellfile。 - 把文本添加进PATH环境变量中任一目录:
shellfile可在任意位置运行。
PATH环境变量:用于保存可以直接运行可执行文件的路径,用:隔开。
24.3 编写shell脚本格式技巧
1、尽量写长选项名
可读性高。
ls -ad等价于ls --all --directory
2、缩进和行连接
命令很长可以写成几行,在行尾使用行连接符\。
第25章 启动一个项目
编写报告生成器:
vim ~/bin/sys_info_page # 编辑shell脚本,详情看下文
chmod 755 ~/bin/sys_info_page # 设置可执行权限
sys_info_page > sys_info_page.html # 输出重定向到一个html文件
firefox sys_info_page.html # 用firefox打开html文件
sys_info_page:
#! /bin/bash
# Program to output a system information page
echo "<HTML>
<HEAD>
...
</HEAD>
<BODY>
...
</BODY>
</HTML>"
1、定义变量/常量
ABC="hahaha":一般大写表示常量;
abc="xixixi":一般小写表示变量。
通过$ABC/$abc进行调用。
2、给变量/常量赋值
shell通过字符串给变量/常量赋值。
3、here文档
可以代替echo输出文本,工作原理是把文本输入到一个命令的stdin中。
command << token # '<<'换成'<<-',则可以忽略text中的Tab,方便对齐缩进。
text
token
所以sys_info_page改写为:
#! /bin/bash
# Program to output a system information page
cat << _EOF_
<HTML>
<HEAD>
...
</HEAD>
<BODY>
...
</BODY>
</HTML>
_EOF_
第26章 自顶向下设计
26.1 shell函数
shell函数定义必须在调用之前。
两种语法形式:
-
# 定义 function funcname { commands return } # 调用 funcname -
# 定义 funcname () { commands return } # 调用 $(funcname)
26.2 局部变量
local varname:通过变量名前面加上local关键字。
第27章 流控制:IF分支语句
27.1 使用if
if commands; then # if条件若有多条命令,根据最后一条执行结果进行评估
commands
elif commands; then
commands
else
commands
fi
27.2 退出状态
$?:查看退出状态。0表示成功,其他数字表示失败。
true/fasle:true命令表示成功(退出状态为0),false命令表示失败(退出状态为1)。
27.3 test命令
if和test命令一起使用。
[expression]:expression是表达式,结果是true(test命令返回退出状态0)/false(test命令返回退出状态1)。
1、文件表达式
评估文件状态。
[-e "$FILE"]:-e判断文件存在。
2、字符串表达式
测试字符串操作。
[-z "$ABC"]:-z判断长度,引号包起变量防止参数为空。
3、整数表达式
27.4 [[]]——新test命令
[[expression]]新增特性:
string=~regex:与正则表达式regex匹配。$FILE == foo.*:模式匹配。
27.5 (())——为整数设计
用于算术真值测试。
27.6 组合表达式
不同命令下用不同符号:
| operation | test | [[]]或者(()) |
|---|---|---|
| AND | -a | && |
| OR | -o | || |
| NOT | ! | ! |
27.7 控制运算符
comm1 && comm2:comm1成功了,comm2才能执行。
comm1 || comm2:comm1失败了,comm2才能执行。
第28章 读取键盘输入
28.1 read——从stdin读取输入值
read [-options] [variable...]
例子🌰:
echo -n "please enter an integer -> " # -n设置不换行输出
read num # 接下来可以使用$num
read var1 var2 var3 # 输入参数不够时,使用默认值(空值)
read # 无变量存储,则存到$REPLY
-------------------------------------------------------------------
read -p "please enter an integer -> " num # -p显示提示
第29章 流控制:WHILE和UNTIL循环
1、while
退出状态不为0时终止。
while commands; do
commands
# 可在循环内使用continue/break.
done
2、until
退出状态为0时终止。
until commands; do
commands
# 可在循环内使用continue/break.
done
3、循环读取文件
while read a b c; do
printf "a: %s\t b: %s\t c: %s\n"\
$a \
$b \
$c
done < ts.txt
第30章 故障诊断
略。
第31章 流控制:case分支
case var in
value1) commands
;;
value2) commands
;;
value3 | value4)
commands
;;
...
*) commands
;;
sesac
第32章 位置参数
命令行默认存有10个参数,用$0/$1/.../$9表示。
第一个$0总是可执行程序所在路径名,其他的根据传参赋值。
1、确定实参数量
$#:得到传入参数数量,不包括$0。
2、shift——处理大量实参
每次只需要处理一个变量即可如$1,每次执行一次shift,所有参数都往上移。
| $1 | $2 | $3 |
|---|---|---|
| a | b | c |
shift:
| $1 | $2 | $3 |
|---|---|---|
| b | c | d |
3、处理多个位置参数
$*:所有参数按单词拆分。
$@:所有参数按单词拆分。
"$*":所有参数合并成1个参数。
"$@":所以参数按引号区分。(最佳!)
第33章 流控制:for循环
1、for:传统shell形式
for var in words; do
commands
done
2、for:C语言形式
for ((expression1; expression2; expression3)); do
commands
done
第34章 字符串和数字
34.1 字符串参数扩展
1、基本参数扩展
${var}:加上{}比较稳健。
2、空变量扩展
${var:-word}:如果变量var未定义或为空,则赋值为word;否则还是原值。
${var:?word}:如果变量var未定义或为空,则把word输出到stderr;否则还是原值。
${var:+word}:如果变量var未定义或为空,无操作;否则赋值为word。
3、返回变量名扩展
${!string*}:返回string开头的变量名,等价于${!string@}。
4、字符串操作
${#string}:字符串string长度。
${string:offset}:从第offset字符开始提取剩余字符串。
${string:offset:length}:从第offset字符开始提取长度为length的字符串。
${string#pattern}:从头删除最短匹配串。
${string##pattern}:从头删除最长匹配串。
${string%pattern}:从尾删除最短匹配串。
${string%%pattern}:从尾删除最长匹配串。
${string/pattern/string}:以string替换第一个匹配串。
${string//pattern/string}:以string替换所有匹配串。
${string/#pattern/string}:以string替换出现在开头的匹配串。
${string/%pattern/string}:以string替换出现在末尾的匹配串。
34.2 算术计算和扩展
$((expression)):基本形式。expression是算术表达式。
$((n#number)):n进制。特别的,默认是十进制,0开头是八进制,0x开头是十六进制。
$((a + b)):a+b。支持各种操作如赋值、加减乘除、位运算、逻辑运算等。
34.3 bc——计算器程序
bc foo.bc
第35章 数组
1、创建数组
a[1]=foo:直接给数组a的元素1赋值进行创建。declare -a a:declare命令创建数组a。
2、数组赋值
name[index]=value:单个赋值。name=(value1 value2...):多个同时赋值。name=([0]=value1 [1]=value2...):指定元素赋值。
3、访问元素
name[index]:某个元素;
4、数组元素集合
"${name[@]}":所有元素集合。用法:for i in "${name[@]}"; do ... done。
5、元素个数
${#name[@]}:返回数组中元素个数。若只有对name[100]=foo创建赋值,name数组元素只有1个。
6、数组元素下标集合
"${!name[@]}":所有元素下标集合。用法:for i in "${!name[@]}"; do ... done。
7、尾部添加元素
name+={var1 var2 var3}
8、数组排序
a_sorted = ($(for i in "${a[@]}"; do echo $i; done | sort)):数组a排序后赋值给a_sorted。
9、删除数组
unset name:删除整个数组;
unset 'name[index]':删除单个元素。
第36章 其他命令
36.1 命令组合使用
两种方式:
- 组命令:
{command1; command2; command3...; } - 子shell:
(command1; command2; command3...; )
注意⚠️:每条命令都要分号结尾;并且最后要加空格!
组命令与子shell的区别:
- 组命令在一个shell里执行所有命令,子shell创建一个新的shell实例执行命令。
- 组命令更快,内存占用更少。
1、用于重定向
ls -l > output.txt
echo "helloworld" >> output.txt
cat foo.txt >> output.txt
------------------------------------------
# 一行搞定
{ls -l; echo "helloworld"; cat foo.txt; } > output.txt
(ls -l; echo "helloworld"; cat foo.txt; ) > output.txt
更常用于管道!{ls -l; echo "helloworld"; cat foo.txt; } | lpr
2、进程替换
由于!**管道中的命令是在子shell内执行!**所以无法对父shell变量进行赋值!
如:
echo "foo" | read
echo $REPLAY # 空值,因为read在子shell执行,"foo"保存在子shell的$REPLAY里,退出则销毁子shell
解决方法:
-
产生stdout:
<(commands)子shell的输出以文件形式保存。 -
吸纳stdin:
>(commands)
例子🌰:
read < <(echo "foo")
echo $REPLAY # 成功读取"foo"
# 常用于read按行读取文本
while a b c; do
...
done < <(foo.txt)
36.2 trap——响应信号
trap string signal:对信号signal作出响应string。
注意⚠️:string是命令加引号构成的字符串。
目的:处理程序不正常终止,对临时文件等的销毁以及提示报错。
36.3 wait——管理异步执行
何谓同步、异步:
- 同步:阻塞模式。进程A需等待B执行完后才可执行。
- 异步:非阻塞模式。无需等待,各自执行。
子脚本可以在父脚本执行时执行额外任务,但是父脚本如果需要子脚本的内容时,
可以用wait命令——父脚本暂停,直到指定进程/子脚本结束。
wait $pid:阻塞至进程号为pid的进程结束运行。
36.4 命名管道——建立两个进程间通信的文件
命名管道,使用两块FIFO缓冲保存通信信息。
# 跨终端/跨进程
process1 > named_pipe
process2 < named_pipe
# 等价于同个终端/同个进程内
process1 | process2
1、mkfifo——设置命名管道
mkfifo pipe1
2、>/<——使用命令管道
终端1:
ls -l > pipe1:数据传至命名管道pipe1并阻塞,直至管道中数据被读取。
终端2:
cat < pipe1:读取命名管道pipe2。
本文介绍Linux shell脚本的基础知识,包括脚本编写、执行、格式技巧及常见控制结构。覆盖变量定义、流程控制、循环结构等内容,适合初学者快速上手。
1534

被折叠的 条评论
为什么被折叠?



