《Linux命令行大全》重点笔记——第四部分 编写shell脚本

《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 组合表达式

不同命令下用不同符号:

operationtest[[]]或者(())
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
abc

shift:

$1$2$3
bcd

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。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值