【树】Linux笔记-3 shell脚本编程
以下内容是参与【生信技能树-全球听第7期】的课程笔记,记录人:小瑛 ,有问题可在公众号后台留言
小白小白,请注意:笔记中出现的所有文件路径,仅作为参考,请勿模仿!
1. Linux 系统环境
文件系统结构:一切皆文件
/ # 虚拟目录的根目录。通常不会在这里存储文件
/bin # 二进制目录,存放许多用户级的GNU工具
/boot # 启动目录,存放启动文件
/dev # 设备目录, Linux在这里创建设备节点
/etc # 系统配置文件目录
/home # 主目录,Linux在这里创建用户目录
/lib # 库目录,存放系统和应用程序的库文件
/media # 媒体目录,可移动媒体设备的常用挂载点
/root # root用户的主目录
/sbin # 系统二进制目录,存放许多GNU管理员级工具
/run # 运行目录,存放系统运作时的运行时数据
/tmp # 临时目录,可以在该目录中创建和删除临时工作文件
/usr # 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里
Linux系统一般有4个主要部分:内核、shell、文件系统和应用程序。
- 内核 是操作系统的核心,具有很多最基本功能,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。
- shell 是系统的用户界面,提供了用户与内核进行交互操作的一种接口。shell也是一门编程语言(脚本编程)
常用命令
lscpu # 查看CPU信息
free -h # 查看内存信息
df -h # 查看硬盘信息
du -h -d 1 # 查看文件大小,显示一层
top # 查看系统进程
ps -ef # 查看系统进程
ps -ef | grep 用户名 # 用于查找该用户提交的进程
2. 变量
调用变量时,要在变量前面加$符号
● 环境变量
用于存储有关shell会话和工作环境的系统变量
● 位置参数变量
用于用于向命令或程序脚本中传递信息
$n # n为数字,$0代表命令本身,$1一$9代表第1一9个参数,10以上的参数需要用大括号包含,如${10}
$* # 这个变量代表命令行中所有的参数,把所有的参数看成一个整体
$@ # 这个变量也代表即令行中所有的参数,不过$@把每个参数区别对待
$# # 这个变量代表命令行中所有参数的个数
● 状态变量
用于记录命令的运行结果
$? # 获取执行上一个指令的执行状态返回值,返回0表示成功,非0则表示失败
$$ # 获取当前执行的shell脚本的进程号PID
$! # 获取上一个后台工作的进程的进程号PID
$_ # 获取在此之前执行的命令或脚本的最后一个参数
● 自定义变量
由用户自行定义的变量,可用于用户编写的脚本,多个命令间的值传递等
a=gene # 赋值的时候=左右不要空格,否则会报错
echo $a
echo 'This is a $a' # 单引号里面的变量$a不会被解释
echo "This is a $a" # 双引号里面的变量$a会被解释,从颜色也可以看出来
● 关于括号
shell编程默认$后面的内容为变量,如果后面还要接其他命令,调用变量的时候需要加{},防止和其他命令粘连,让系统把其他命令也误认为是变量。
shell中的括号(小括号,中括号,大括号) linux中的(),(()),[],[[]],{}的作用 - 雅思敏 - 博客园
https://www.cnblogs.com/yasmi/articles/5129571.html
3. 结构化语句
● 条件语句 if
之前遇到的 awk 里面的 if 和这里的 if 在语法和使用上不一样。
命令格式
# 形式 1
if command # 条件
then
commands
fi
_________________________
# 形式 2
if command # 条件
then
commands
else
commands
fi
_________________________
# 形式 3
if command1 # 条件1
then
commands
else
if command2 # 条件2
then
commands
fi
fi
常见的条件(中括号两边的空格一定要留)
# 1.数值判断
[ INT1 -eq INT2 ] # INT1 和 INT2 两数相等返回为真 =
[ INT1 -ne INT2 ] # INT1 和 INT2 两数不等返回为真 ≠
[ INT1 -gt INT2 ] # INT1 大于 INT2 返回为真 >
[ INT1 -ge INT2 ] # INT1 大于等于 INT2 返回为真 ≥
[ INT1 -lt INT2 ] # INT1 小于 INT2 返回为真 <
[ INT1 -le INT2 ] # INT1 小于等于 INT2 返回为真 ≤
_______________________________________________________________________
# 2.字符判断
[ -z STRING ] # 如果STRING的长度为零则返回为真,即空是真
[ -n STRING ] # 如果STRING的长度非零则返回为真,即非空是真
[ STRING1 ] # 如果字符串不为空则返回为真,与-n类似
[ STRING1 === STRING2 ] # 如果两个字符串相同则返回为真
[ STRING1 != STRING2 ] # 如果字符串不相同则返回为真
[ STRING1 < STRING2 ] # 如果STRING1字典排序在STRING2前面则返回真,>同理
_______________________________________________________________________
# 3.文件判断
[ -a FILE ] # 如果FILE存在则为真
[ -d FILE ] # 如果FILE存在且是一个目录则返回为真
[ -f FILE ] # 如果FILE存在且是一个普通文件则返回为真
● 循环语句 for / while
for 循环语句的常见格式
# 一般格式
for i in list
do
commands
done
# 示例
for i in 1 2 3 4 5 # 1 2 3 4 5 可以表示为{1..5}
do
echo ${i} "Hello Word!" # 这下面还可以写其他命令
done
# 单行形式
for i in {1..5};do echo ${i} "Hello Word!";done
# 输出
1 Hello Word!
2 Hello Word!
3 Hello Word!
4 Hello Word!
5 Hello Word!
# 如果list的内容很杂,可以将内容赋值给一个变量
list="CDS exon gene start_codon stop_codon transcript UTR"
for i in ${list}
do
echo "This is ${i}"
done
# 利用反引号来合并代码
ls file* # 列出当前路径下file开头的文件,接下来需要对这些文件批量操作
for i in `ls file*` # 把上一行命令写入反引号内会被优先执行
do
mv ${i} ${i}.txt # 批量重命名加上.txt后缀,此处可以先用echo替代mv,看到效果后再用mv
done
while 循环语句的常见格式
# 格式 1
while read id
do
commands
done
# 格式 2 (不推荐)
while rcommand
do
other commands
done
# 格式 1 示例
ls file*
ls file* | while read x # x是自己定义的变量名, while read 是按行读取
do
mv ${x} ${x}.txt
done
# 以下的代码方便理解while read 是按行读取
cat test.txt | while read x
do
echo ${x} # 直接打印测试文件test.txt中的内容
sleep 2s # 每执行一次echo ${x}都睡2s
done
# 输出以下内容,每行显示之间间隔2s
1 Hello Word!
2 Hello Word!
3 Hello Word!
4 Hello Word!
5 Hello Word!
● 参数扩展
掐头去尾
${变量#关键字} # 若变量内容从头开始的数据符合"关键字”,则将符合的最短数据删除
${变量##关键字} # 若--------头-------------------,----------长------
${变量%关键字} # 若--------尾-------------------,----------短------
${变量%%关键字} # 若--------尾-------------------,----------长------
替换(去中间)
${变量/旧字符串/新字符串} # 若变量内容符合"旧字符串”,则首个旧字符串会被新字符串替换。
${变量//旧字符串/新字符串} # --------------------,-全部---------------------。
# “去中间”的示例
# 创建 10 个文件 test_file_1 ~ test_file_10 ,使用循环语句(建议用 while read id),将上面的 test_file_1 ~ test_file_10 进行重命名,如:test_file_1 改为 test_1
touch test_file_{1..10}
ls test_file_* | while read x
do
mv ${x} ${x/_file/} # 把_file替换为空,起到删除的效果
done
切片(取索引)
索引下标从0开始,R是从1开始。
${变量:索引} # 截取变量从索引位置到末尾的所有字符
${变量:索引:n} # ---------------开始的n个字符
${变量:索引:(-n)} # ---------------到倒数第n+1位的所有字符
${变量:索引:-n} # 同上
# 示例
id=Data.tar.gz
echo ${#id} # 显示字符长度:11
echo ${id:3} # 显示索引3,也就是第4位开始到最后
echo ${id:3:5} # 显示索引3,也就是第4位开始的5个字符
echo ${id:3:(-1)} # 显示索引3,也就是第4位开始到倒数第 1+1=2 个字符
echo ${id:3:-1} # 同上
4. shell脚本编程
● Vim 编辑器
是从vi发展出来的文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。本质上和Rstudio、pycharm一样都是代码编辑器。
工作模式
一般流程:vim 文件名 → i → 键入内容 → ESC → :wq
vim编写的内容如果符合某一种编程语言的语法,就可以用对应的语言去解释,文件名后缀也尽量体现文本格式
- bash 文件.sh shell 语言
- Python 文件.py Python 语言
- R 文件.r R 语言
键盘图
查看帮助文档
vimtutor zh_CN # 查看中文帮助文档
# 该文档属于vim的工作模式,任何操作要符合vim语法规则
● shell脚本
编写shell脚本的规范
- 文件名以.sh结尾
- 脚本首行:#!/bin/bash ,#! 是Linux的Shebang 符号,指定解释器,/bin/是bash所在的文件夹
- 脚本的正文
输出文件
bash test.sh 1>1.log 2>2.log # 如果test.sh文件的输出很多,直接输出到屏幕会刷屏
# 将结果保存到日志文件中
# 1:标准输出流 正确输出 保存到 1.log中
# 2:标准误输出流 错误输出 保存到 2.log中
bash test.sh 1>output.log 2>&1 # 不管正确错误,结果文件都存放到output.log中
修改文件权限
chmod 764 test.sh # 修改文件的权限为:自己全可以,同组可读可写,别人可读
# 执行后文件会变成绿色
~/test.sh # 修改权限之后就可以用路径调用
参数传递
cat test.sh
# 显示内容如下
#!/bin/bash
cat $1 # test.sh内的命令正文,查看第一个文件内容 $1 位置参数
# 运行这个脚本
bash test.sh 需要执行的文件1 # $1 对应 需要执行的文件1
● 任务提交
nohup 需要运行的命令 & # 挂载操作的格式
# 返回值
[1] 11169 # 数字是任务号
nohup: ignoring input and appending output to 'nohup.out' # 所有输出都保存到 nohup.out
# 查看后台处理进程
top # 实时显示系统中各个进程的资源占用状况,按q退出
ps -ef # Process Status 列出当前系统中运行的进程列表
# 返回值
[1]+ Done # 成功
[1]+ Exit # 失败
# 终止任务
kill PID # PID是ps -ef后的第一个数字,不是任务号
往期回顾
Linux笔记-1 https://www.jianshu.com/p/78aad4b705af
Linux笔记-2 软件安装 https://www.jianshu.com/p/403fa1322155