1.3.Linux Bash
在介绍bash之前,需要先介绍linux系统的shell。这里的shell(壳)是相对于内核(kernel)来说的。shell可以理解为系统下的一个命令解析器。就linux操作系统的常规使用而言(包括生物信息数据分析),我们极少需要直接和linux的内核进行交互,绝大部分情况下都是在通过shell和操作系统打交道。
linux系统上有很多种Shell。首个shell,即Bourne Shell,于1978年在V7(AT&T的第7版)UNIX上推出。后来,又演变出C shell、bash等不同版本的shell。
shell可以通过交互式(interactive)的方式使用,即我们在终端中输入一个命令,shell将这个命令解释给操作系统,操作系统执行命令,这是我们前面介绍linux基本操作时的使用方式。
shell也可以通过非交互式(non-interactive)的方式使用,即我们将需要执行的命令通过一个文本文件提供给shell,shell根据这个文本文件执行相应的命令。这个文本文件就是shell脚本。
有时我们对程序的调用会比较复杂,并且会反复使用(例如执行一个生物信息分析的流程),还可能涉及到循环,条件判断等操作。这时我们不可能每次还一行行的在终端中输入命令,而通常会使用shell脚本。我们本节主要就来学习怎样写一些简单的shell脚本。
bash,全称为Bourne-Again Shell。它是一个为GNU项目编写的Unix shell。bash是许多Linux系统的默认Shell,这也是我们介绍它主要的原因。
1) bash examples
(1) example 1: run a bash script
新建文件bash.sh
$ touch bash.sh
为该文件添加可执行权限
chmod u+x bash.sh
编辑bash.sh,内容如下:
提示:
用vim编辑脚本:
vim bash.sh
i
# 在vim中输入i 即进入insert(写入)模式,即可对bash.sh 文档进行编辑
#!/bin/bash
echo "hello bash"
exit 0
:wq
# 保存并退出
说明:
#!/bin/bash
: 脚本解释器的声明语句,它告诉操作系统用/bin/bash
这个解释器去运行我们的脚本。必须写在文件的第一行。echo "hello bash"
: 表示在终端输出“hello bash”exit 0
: 表示返回0。在linux中,通常来说返回值0表示执行成功,其他表示失败。bash脚本执行成功默认就会返回0,所以这里的exit 0
是可以省略的。执行bash脚本
# method 1: 人为指定解释器 bash bash.sh # method 2: 使用脚本内指定的解释器(脚本第一行的#!/bin/bash已经告诉操作系统使用/bin/bash这个解释器) # 这种方法需要脚本文件有可执行的权限,这是我们前面执行命令chmod u+x bash.sh的目的所在 ./bash.sh
在终端输出“hello bash”即运行成功
(2) example 2: define a variable
在终端中输入以下命令,创建测试文件a1.txt,b1.txt,...,e1.txt。
echo -e 'a1\n1' > a1.txt
echo -e 'b1\n2' > b1.txt
echo -e 'c1\n3' > c1.txt
echo -e 'd1\n4' > d1.txt
echo -e 'e1\n5' > e1.txt
新建一个
read.sh
脚本,复制以下内容,理解每一步的操作:
#!/bin/bash
# 定义文件名变量
# bash中=是赋值操作符,注意=号两边不能有空格
file1=a1.txt
file2=b1.txt
file3=c1.txt
file4=d1.txt
file5=e1.txt
# 对文件进行操作
## 显示a1.txt第一行。
head -n 1 ${file1}
## 将 b1.txt 的内容输出到终端
# 注意在bash中引用一个已经定义的变量需要用$variable或${variable},否则bash会将其解释为一个字符串:
cat ${file2}
## 将 c1.txt 的最后的内容输出。
tail ${file3}
## 将 d1.txt 和 e1.txt 合并,然后输出到新的文件中 f1.txt
cat ${file4} ${file5} > f1.txt
在终端中输入以下命令,执行
read.sh
脚本:
bash read.sh
或者
chmod u+x read.sh
./read.sh
2) if...else...
基本格式
单个条件判断
if condition
then
...
fi
也可以写成:
if condition;then
...
fi
对不符合条件的情况执行另一种操作:
if condition;then
...
else
...
fi
多个条件判断:
if condition1;then
...
elif condition2;then
...
else
...
fi
以下列举了一些常见的条件判断语句,条件判断一般写在方括号内(参见下面的示例)
-d file
判断是否为目录
-f file
判断是否为文件
-w file
判断是否有写的权限
-x file
判断是否有执行的权限
number1 -eq number2
number1 等于 number2
number1 -gt number2
number1 大于 number2
number1 -lt number2
number1 小于 number2
示例: 判断文件test.sh是否存在,存在则输出“file exist”;没有则输出“file not exist”。
#!/bin/bash
if [ -f test.txt ];then
echo "file exist"
else
echo "file not exist"
fi
exit 0 # 可以省略
示例: 提示用户输入值。若输入的值小于0,则输出“negtive number”;若等于0,则输出“number zero”,否则,输出“positive number”。
#!/bin/bash
# 提示用户输入一个值
echo -n "please input a number:"
# 保存用户输入的值到num中
read num
if [ "$num" -lt "0" ];then
# 小于0,则输出“negtive number”
echo "negtive number"
elif [ "$num" -gt "0" ];then
# 大于0,则输出“positive number”
echo "positive number"
else
# 大于0,则输出"number zero"
echo "number zero"
fi
exit 0
3) for loop
基本格式
for variable in aa bb cc dd
do
echo $variable
done
# 这里bash会用空格作为分隔符,把字符串解释成"aa bb cc dd"解释成一个列表,包含"aa","bb","cc","dd"四个变量
# variable会依次取这四个值,执行代码块中的命令
示例1: 输入当前文件夹的一级子目录中文件的名字
#!/bin/bash
# 将ls的结果保存到变量CUR_DIR中
CUR_DIR=`ls`
# 显示ls的结果
echo $CUR_DIR
for val in $CUR_DIR
do
# 若val是文件,则输出该文件名
if [ -f $val ];then
echo "FILE: $val"
fi
done
exit 0
示例2: shuffle一个序列
#!/bin/bash
# shuffle a sequence
# input sequence
s="CGAUGCUAGCUAGCUAGUC"
# start index
si=0
L=${#s} # length of the sequence
# end index
ei=$(($L-1))
shuffled=""
for i in `seq $si $ei | shuf `;do
# seq generate integers range from $si to $ei (include both $si and $ei)
# shuf command randomize the order of these integers
shuffled=$shuffled${s:$i:1}
# ${s:$i:1}: variable expansion, take substring start from $i with length 1, this operator in bash use 0 based coordinate
# $shuffled${s:$i:1}: concatenate string $shuffled and string ${s:$i:1}
done
echo "original sequence: $s"
echo "shuffled sequence: $shuffled"
4) break and continue
基本格式
break命令允许跳出循环。 continue命令类似于 break命令,只有一点重要差别,它不会跳出循环,只是跳过这个循环步。
示例:
从0开始逐步递增,当数值等于5时停止。bash脚本内容如下:
#!/bin/bash
# 设置起始值为0
val=0
while true
do
if [ "$val" -eq "5" ];then
# 如果val=5,则跳出循环
break;
else
# 输出数值
echo "val=$val"
# 将数值加1
((val++))
fi
done
exit 0
示例:
从0开始逐步递增到10:当数值为5时,将数值递增2;否则,输出数值。
#!/bin/bash
# 设置起始值为0
val=0
while [ "$val" -le "10" ]
do
if [ "$val" -eq "5" ];then
# 如果val=5,则将数值加2
((val=$val+2))
continue;
else
# 输出数值
echo "val=$val"
# 将数值加1
((val++))
fi
done
exit 0
5) More Reading
《鸟哥的Linux私房菜-基础学习篇》 (11-13章推荐章节)
Linux 推荐章节:
第11章 认识与学习bash; 第12章 正则表达式与文件格式化处理 第13章 学习shell script
6) Homework
参考和学习本章内容,写出一个 bash 脚本,可以使它自动读取一个文件夹(例如 bash_homework/)的内容,将该文件夹下文件的名字输出到 filenames.txt, 子文件夹的名字输出到 dirname.txt 。
提示和要求:下载bash_homework.zip并解压(可以从链接 Files Needed 的
Files
路径下的相应文件夹中下载)。将 bash 脚本,filename.txt, dirname.txt 写到同一个文件中上交。文件格式: md(推荐),word, pdf, txt.
7) References
Last updated
Was this helpful?