本教程宗旨 (请仔细阅读)

本教程不是一个完备的Linux使用教程,而是侧重于一般教程默认读者会了的信息,包括基本概念的解释 (方便初学者了解自己的操作)、命令的各种错误及解决 (通常写教程的都是对这一领域比较熟悉的,一般不会提到这些初学者刚开始不好理解的简单错误)、部分常用命令 (会提到基本用法,具体的使用还请查看手册或在线搜索)、常用快捷键 (简化操作)和组合命令 (快速的批处理等,初学者一般不会想到、高级学者又不屑于提起的部分)。

为什么要用Linux系统

个人认为,Linux操作系统和类Linux操作系统的命令行界面是最适合进行生物信息分析的操作系统。原因有三点:

  • 长期运行的稳定性
  • 多数软件只有Linux版本
  • 强大的Bash命令简化繁琐的操作,尤其是大大简化重复性工作

但对于初学者来说,接触和理解Linux操作系统需要一些时间和摸索。陡然从可视化点选操作的Windows进入到只有命令行界面的Linux,最大的陌生感是不知道做什么,不知道文件在哪?本文希望能通过几个示例帮助大家适应Linux系统。

如何获取Linux系统

  • 如果自己的单位有共有服务器,可以尝试申请账号。
  • 自己的电脑安装双系统或虚拟机
  • 购买一块云服务器
  • 试验下在线学习平台实验楼 https://www.shiyanlou.com (里面也有不少Linux教程,任意点一个进去,双击桌面的Xfce图标,都可以启动Linux终端)
  • <生信宝典>微信公众号后台回复向管理员索要

初识Linux系统

登录Linux系统后,呈现在眼前的是这样一个界面:

Last login: Mon Jun  5 16:56:56 2017 from 219.241.208.209

Welcome to aliyun Elastic Compute Service!

ct@ehbio:~$ 

首先解释下出现的这几个字母和符号:

  • ct: 用户名
  • ehbio:如果是登录的远程服务器,则为宿主机的名字
  • ~: 代表家目录, 在我们进入新的目录后,这个地方会跟着改变
  • $: 用来指示普通用户输入命令的地方;对根用户来说一般是#
  • http://bashrcgenerator.com/可视化定制不同的显示方式。

我的电脑在哪?

打开Windows,首先看到的是桌面;不爱整理文件的我,桌面的东西已经多到需要2个屏幕才能显示的完。另外一个常用的就是我的电脑,然后打开D盘,依次点开对应的文件夹,然后点开文件。

Linux的文件系统组织方式与Windows略有不同,登录进去就是家目录,可视为Windows下的桌面。在这个目录下,我们可以新建文件、新建文件夹,就像在桌面上的操作一样。

注:

  • 这里我们假设所有用到的文件和文件夹都放置于家目录下
  • Linux的家目录严格来说可能类似于Windows下的C:\Users\ct

如果想查看当前目录下都有什么内容,输入命令 ls,回车即可 (ls可以理解为单词list的缩写)。当前目录下什么也没有,所以没有任何输出。

ct@ehbio:~$ ls

如果错把l看成了i,输入了is,则会出现下面的提示未找到命令。如果输入的是Linux基本命令,出现这个提示,基本可以判定是命令输入错了,瞪大眼睛仔细看就是了。 在敲完命令回车后,注意查看终端的输出,以判断是否有问题。

ct@ehbio:~$ is
-bash: is: 未找到命令
# 大小写敏感
ct@ehbio:~$ lS
-bash: lS: 未找到命令

当前目录下只有一个文件,看不出效果,我们可以新建几个文件和文件夹,来查看下。

mkdir是新建一个目录 (make a directory);data是目录的名字。 如果目录存在,则会出现提示,”无法创建已存在的目录”。这时可以使用参数-p忽略这个错误。

ct@ehbio:~$ mkdir data
ct@ehbio:~$ mkdir ls
data
ct@ehbio:~$ mkdir data
mkdir: 无法创建目录"data" : 文件已存在
ct@ehbio:~$ mkdir -p data

cat是一个命令,主要用来查看文件;在这与<<END连用用于读入大段数据。输入cat <<END之后,回车,会看到终端出现一个大于号,大于号后面可以输入内容,再回车,继续输入内容,直到我们输入END (大写的,与上面一致),输入过程结束,我们输入的内容都显示在了屏幕上。

ct@ehbio:~$ mkdir data
ct@ehbio:~$ cat <<END
> a
> bc
> END
a
bc

`>`是一个重定向符号,即把前面命令的输出写入到`>`后面的文件中。如下所示,新建了一个`Fasta`格式的文件。
`ls -l`列出文件的详细信息;`-l`表示命令行参数,是程序预留的一些选项,保证在不更改程序的情况下获得更灵活的操作。可使用`man ls`查看`ls`所有的命令行参数, 上下箭头翻页,按`q`退出查看。(man: manual, 手册)

```bash
ct@ehbio:~$ cat <<END >data/test.fa
> >SOX2
> ACGTCGGCGGAGGGTGGSCGGGGGGGGAGAGGT
> ACGATGAGGAGTAGGAGAGAGGAGG
> >OCT4
> ACGTAGGATGGAGGAGAGGGAGGGGGGAGGAGAGGAA
> AGAGTAGAGAGA
> >NANOG
> ACGATGCGATGCAGCGTTTTTTTTTGGTTGGATCT
> CAGGTAGGAGCGAGGAGGCAGCGGCGGATGCAGGCA
> ACGGTAGCGAGTC
> >mYC HAHA
> ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
> CAGGACAGGAGCTA
> end
> END
## 注意命令和参数之间的空格
ct@ehbio:~/data$ ls-l
-bash: ls-l: 未找到命令
ct@ehbio:~$ ls -l
总用量 4
## d: dir; 表示data是个目录
## rwx:表示目录的权限,暂时忽略,或自己在线搜索
drwxrwxr-x 2 ct ct 4096 6月   8 14:52 data
ct@ehbio:~$ ls -l data
总用量 4
## 开头的`-`表示test.fa是个文件
-rw-rw-r-- 1 ct ct 284 6月   8 14:48 test.fa

查看写入的文件的内容,cat 文件名;需要注意的是文件所在的目录,默认是当前目录;如下面第一个命令,会提示cat: test.fa: 没有那个文件或目录,是因为当前目录下不存在文件test.fa。(注意文件末尾的end)

ct@ehbio:~$ cat test.fa
cat: test.fa: 没有那个文件或目录
ct@ehbio:~$ cat data/test.fa 
>SOX2
ACGTCGGCGGAGGGTGGSCGGGGGGGGAGAGGT
ACGATGAGGAGTAGGAGAGAGGAGG
>OCT4
ACGTAGGATGGAGGAGAGGGAGGGGGGAGGAGAGGAA
AGAGTAGAGAGA
>NANOG
ACGATGCGATGCAGCGTTTTTTTTTGGTTGGATCT
CAGGTAGGAGCGAGGAGGCAGCGGCGGATGCAGGCA
ACGGTAGCGAGTC
>mYC HAHA
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

test.fa在目录data下,可以先进入data目录,然后再查看文件。类比于Windows下先点开一个文件夹,再点开下面的文件。

cd (change dir)切换目录。

head查看文件最开始的几行,默认为10行,可使用-n 6指定查看前6行。

ct@ehbio:~$ cd data
ct@ehbio:~/data$ head -n 6 test.fa 
>SOX2
ACGTCGGCGGAGGGTGGSCGGGGGGGGAGAGGT
ACGATGAGGAGTAGGAGAGAGGAGG
>OCT4
ACGTAGGATGGAGGAGAGGGAGGGGGGAGGAGAGGAA
AGAGTAGAGAGA

另外lessmore也可以用来查看文件,尤其是文件内容特别多的时候。

ct@ehbio:~/data$ less test.fa 
# q: 退出
# 上下箭头、空格翻页

获取可用命令行参数

前面使用的命令,有几个用到了参数如ls -l, head -n 6等,需要注意的是命令跟参数之间要有空格

终端运行man ls可以查看ls所有可用的参数,上下箭头翻页,按q退出查看。(man: manual, 手册)

ct@ehbio:~/data$ man ls
NAME
 ls - list directory contents

SYNOPSIS
 ls [OPTION]... [FILE]...

DESCRIPTION
 List  information  about  the  FILEs  (the current directory by default).
 Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.

 Mandatory arguments to long options are mandatory for short options too.

 -a, --all
  do not ignore entries starting with .

 -A, --almost-all
  do not list implied . and ..

 --author
  with -l, print the author of each file

 -b, --escape
  print C-style escapes for nongraphic characters
 ....
	

文件上下翻转和左右翻转

两个有意思的命令,tac: 文件翻转,第一行变为最后一行,第二行变为倒数第二行;rev每列反转,第一个字符变为最后一个字符,第二个字符变为倒数第二个字符。

ct@ehbio:~/data$ cat <<END | tac
> first
> second
> third
> END
third
second
first
ct@ehbio:~/data$ cat <<END | rev
> abcde
> xyz
> END
edcba
zyx

其它新建文件的方式

nano类似于Windows下记事本的功能,nano filename就可以新建一个文件,并在里面写内容;ctrl+x退出,根据提示按Y保存。

vim 功能更强大的文本编辑器。vim filename就可以新建一个文件, 敲击键盘字母i,进入写作模式。写完后,敲击键盘Esc, 退出写作模式,然后输入:w (会显示在屏幕左下角),回车保存。vim的常用方法,以后会单写一个,这里点到为止。

Linux下文件操作

常用的文件操作有移动文件到另一个文件夹、复制文件到另一个文件夹、文件重命名等。

cp (copy): 拷贝文件或文件夹 (cp -r 拷贝文件夹时的参数,递归拷贝)

# 列出当前目录下有的文件和文件夹
ct@ehbio:~$ ls
data

# 新建一个文件夹
ct@ehbio:~$ mkdir ehbio_project

# 列出当前目录下有的文件和文件夹, 及其子文件夹的内容
# data目录下有一个文件,ehbio_project目录下无文件
ct@ehbio:~$ ls *
data:
test.fa

ehbio_project:

# 拷贝data目录下的文件test.fa到ehbio_project目录下
ct@ehbio:~$ cp data/test.fa ehbio_project/

# 列出当前目录下有的文件和文件夹, 及其子文件夹的内容
# data目录下有一个文件,ehbio_project目录下无文件
ct@ehbio:~$ ls *
data:
test.fa

ehbio_project:
test.fa

mv (move): 移动文件或文件夹

# 重命名data目录下的文件test.fa为first.fa
# mv除了可以移动文件,也可以做单个文件的重命名
ct@ehbio:~$ mv data/test.fa data/first.fa

# 列出当前目录下有的文件和文件夹,  及其子文件夹的内容
ct@ehbio:~$ ls *
data:
first.fa

ehbio_project:
test.fa

rename: 文件重命名 (常用于批量重命名,不同的系统可能用法略有不同,使用前先man rename查看使用方法)

# 进入另一个目录
ct@ehbio:~$ cd ehbio_project/
ct@ehbio:~/ehbio_project$ ls
test.fa

# 给文件做一份拷贝
ct@ehbio:~/ehbio_project$ cp test.fa second.fa
ct@ehbio:~/ehbio_project$ ls
second.fa  test.fa

# 给文件多拷贝几次,无聊的操作,就是为了给rename提供发挥作用的机会
ct@ehbio:~/ehbio_project$ cp test.fa test2.fa
ct@ehbio:~/ehbio_project$ cp test.fa test3.fa
ct@ehbio:~/ehbio_project$ cp test.fa test4.fa

# cp 后面需要2个参数,被拷贝的文件和要被拷贝到的目录或文件
# 出现下面的错误,表示缺少目标路径或文件
ct@ehbio:~/ehbio_project$ cp ehbio.fa 
cp: 在" ehbio.fa"  后缺少了要操作的目标文件
Try 'cp --help' for more information.

ct@ehbio:~/ehbio_project$ ls
second.fa  test2.fa  test3.fa  test4.fa  test.fa

# 用rename进行文件批量重命名
ct@ehbio:~/ehbio_project$ rename 'test' 'ehbio' test*.fa
ct@ehbio:~/ehbio_project$ ls
ehbio2.fa  ehbio3.fa  ehbio4.fa  ehbio.fa  second.fa

ln (link): 给文件建立快捷方式 (ln -s source_file target 创建软连接)。

在建立软连接时,原文件要使用全路径。全路径指以/开头的路径。

建立软连接,是为了在不增加硬盘存储的情况下,简化文件访问方式的一个办法。把其它文件夹下的文件链接到当前目录,使用时只需要写文件的名字就可以了,不需要再写长串的目录了。

../: 表示上一层目录;../../: 表示上面两层目录

pwd (print current/working directory): 输出当前所在的目录

\为键盘Esc下第一个按键 (与家目录~`符号同一个键),写在反引号内的命令会被运行,运行结果会放置在反引号所在的位置

# 建立软连接,把当前目录下的ehbio2.fa,链接到上一层目录的data下面

# 这是一个无效的软连接,
ct@ehbio:~/ehbio_project$ ln -s ehbio2.fa ../data

# 在使用ls查看时,无效的软连接的文件名下面是黑色的背景。
ct@ehbio:~/ehbio_project$ ls -l ../data/
总用量 4
lrwxrwxrwx 1 ct ct   9 6月   9 17:55 ehbio2.fa -> ehbio2.fa
-rw-rw-r-- 1 ct ct 284 6月   8 14:48 first.fa

# 输出当前所在的目录
ct@ehbio:~/ehbio_project$ pwd
/home/ct/ehbio_project

# 建立软连接时,原始文件一定使用全路径。全路径指以/开头的路径。
ct@ehbio:~/ehbio_project$ ln -s /home/ct/ehbio_project/ehbio2.fa ../data
ln: 无法创建符号链接" ../data/ehbio2.fa" : 文件已存在

# 上面的错误信息时,已经存在这么一个链接了(虽然是无效的),但再建新的链接时还会提示
# 使用`-f` (force)强制覆盖已有的链接
ct@ehbio:~/ehbio_project$ ln -fs `pwd`/ehbio2.fa ../data

# 再次查看时,就正常了。文件名下面没有了背景色,并且有个右箭头指向原始文件
# `lrwxrwxrwx`中的`l`表示软连接。
ct@ehbio:~/ehbio_project$ ls -l ../data/
总用量 4
lrwxrwxrwx 1 ct ct  32 6月   9 17:56 ehbio2.fa -> /home/ct/ehbio_project/ehbio2.fa
-rw-rw-r-- 1 ct ct 284 6月   8 14:48 first.fa

# 通常为了简化写法,使用`pwd`代替全路径
# `为键盘Esc下面的按键,写在反引号内的命令会被运行,运行结果会放置在反引号所在的位置
ct@ehbio:~/ehbio_project$ ln -s `pwd`/ehbio2.fa ../data
ln: 无法创建符号链接" ../data/ehbio2.fa" : 文件已存在
ct@ehbio:~/ehbio_project$ ln -fs `pwd`/ehbio2.fa ../data
ct@ehbio:~/ehbio_project$ ls -l ../data/
总用量 4
lrwxrwxrwx 1 ct ct  32 6月   9 17:56 ehbio2.fa -> /home/ct/ehbio_project/ehbio2.fa
-rw-rw-r-- 1 ct ct 284 6月   8 14:48 first.fa

Linux下命令的一些异常情况

命令不全:在命令没有输入完 (引号或括号没有配对),就不小心按下了Enter键,终端会提示出一个>代表命令不完整,这是可以继续输入,也可以ctrl+c终止输入,重新再来。(下面sed命令使用时,还有另外一种命令不全的问题)

ct@ehbio:~/ehbio_project$ rename 'ehbio2
>'
ct@ehbio:~/ehbio_project$ rename 'ehbio2
> ^C
ct@ehbio:~/ehbio_project$

文件名输入错误: 多一个字母、少一个字母、大小写问题

ct@ehbio:~/ehbio_project$ls
ehbio2.fa  ehbio3.fa  ehbio4.fa  ehbio.fa  second.fa

# 重命名没有生效
ct@ehbio:~/ehbio_project$ rename 'ehbio2' 'ehbio5' ebio2.fa
ct@ehbio:~/ehbio_project$ ls
ehbio2.fa  ehbio3.fa  ehbio4.fa  ehbio.fa  second.fa

# 仔细看是ehbio2.fa写成了ebio2.fa,更正后即可。
Z8vb3e9jtel4m99ss6e7eZ:~/ehbio_project$ rename 'ehbio2' 'ehbio5' ehbio2.fa
ct@ehbio:~/ehbio_project$ ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio.fa  second.fa

所在目录不对: 访问的文件不存在于当前目录,而又没有提供绝对路径, 或软连接失效

ct@ehbio:~/ehbio_project$ ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio6.fa  ehbio.fa  second.fa
ct@ehbio:~/ehbio_project$ ls ../data
ehbio2.fa  first.fa

# 当前目录没有ehbio2.fa
ct@ehbio:~/ehbio_project$ less ehbio2.fa
ehbio2.fa: 没有那个文件或目录

# ehbio2.fa在上一层目录的data目录下
ct@ehbio:~/ehbio_project$ ls ../data/ehbio2.fa 
../data/ehbio2.fa

# 加上路径依然访问不了 
ct@ehbio:~/ehbio_project$ less ../data/ehbio2.fa 
../data/ehbio2.fa: 没有那个文件或目录

# 上面的问题是软连接失效,在之前的操作中删掉了原始的ehbio2.fa,所以快捷方式失效

# 正确的访问
ct@ehbio:~/ehbio_project$ tail -n 3 ../data/first.fa 
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

Linux下文件内容操作

常用的文件内容操作有文件压缩解压缩、文件大小行数统计、文件内容查询等。

gzip: 压缩文件; gunzip: 解压缩文件

# gzip -c 把压缩的文件输出到标准输出 (一般是屏幕)
# '>' 输出重定向,输出写入文件

ct@ehbio:~/ehbio_project$ gzip -c ehbio.fa >ehbio.fa.gz

# 多了一个.gz文件
ct@ehbio:~/ehbio_project$ ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio.fa  ehbio.fa.gz  second.fa

#解压缩
ct@ehbio:~/ehbio_project$ gunzip ehbio.fa.gz
gzip: ehbio.fa already exists; do you wish to overwrite (y or n)? y
ct@ehbio:~/ehbio_project$ ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio.fa  second.fa

wc (word count): 一般使用wc -l获取文件的行数

# 输出文件有14行
ct@ehbio:~/ehbio_project$ wc -l ehbio.fa
14 ehbio.fa

获取文件中包含大于号 (>)的行, grep (print lines matching a pattern)。 grep的用法很多,支持正则表达式匹配,这里不展开,可以自己查阅资料,或在后期的教程涉及到时再学习。

ct@ehbio:~/ehbio_project$ grep '>' ehbio.fa
>SOX2
>OCT4
>NANOG
>mYC HAHA

# 获取包含>的行的行数 (-c: count lines)
ct@ehbio:~/ehbio_project$ grep -c '>' ehbio.fa
4

# 是不是还记得当时新建文件时,末尾多了一行end,删除end所在行
ct@ehbio:~/ehbio_project$ less ehbio.fa 

# -v: 不输出匹配上的行
ct@ehbio:~/ehbio_project$ grep -v 'end' ehbio.fa >ehbio6.fa
ct@ehbio:~/ehbio_project$ cat ehbio6.fa 
>SOX2
ACGTCGGCGGAGGGTGGSCGGGGGGGGAGAGGT
ACGATGAGGAGTAGGAGAGAGGAGG
>OCT4
ACGTAGGATGGAGGAGAGGGAGGGGGGAGGAGAGGAA
AGAGTAGAGAGA
>NANOG
ACGATGCGATGCAGCGTTTTTTTTTGGTTGGATCT
CAGGTAGGAGCGAGGAGGCAGCGGCGGATGCAGGCA
ACGGTAGCGAGTC
>mYC HAHA
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA

替换文件中的字符: sed是一个功能强大的文件内容编辑工具,常用于替换、取得行号等操作。

# 第一个错误,漏掉了文件名
# 程序静止在这,等待用户的进一步输入
# ctrl+c杀掉当前命令
ct@ehbio:~/ehbio_project$ sed 's/ HAHA//' | tail -n 3

^C

# 第二个错误,文件名和单引号之间没有空格,使得sed判断命令错误

ct@ehbio:~/ehbio_project$ sed 's/ HAHA//'ehbio.fa  | tail -n 3
sed:-e 表达式 #1,字符 11:“s”的未知选项

# 正确操作,

ct@ehbio:~/ehbio_project$ sed 's/ HAHA//' ehbio.fa  | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

另外一个方式,去除HAHA,使用cut命令 (cut更适合与矩阵操作,去除其中的一列或者多列)。

-f: 指定取出哪一列,使用方法为-f 2 (取出第2列),-f 2-5 (取出第2-5列),-f 2,5 (取出第2和第5列)。

-d: 设定分隔符, 默认为TAB键。如果一行没有指定的分隔符,整行都为第一列。

ct@ehbio:~/ehbio_project$ cut -f 1 -d ' ' ehbio.fa | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

Linux终端常用快捷操作

  • 命令或文件名自动补全:在输入命令或文件名的前几个字母后,按Tab键,系统会自动补全或提示补全
  • 上下箭头:使用上下箭头可以回溯之前的命令,增加命令的重用,减少输入工作量
  • !加之前输入过的命令的前几个字母,快速获取前面的命令
ct@ehbio:~/ehbio_project$ cut -f 1 -d ' ' ehbio.fa | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end
ct@ehbio:~/ehbio_project$ man cut
# 直接跳到上面运行的cut命令,再执行一次
ct@ehbio:~/ehbio_project$ !cut
cut -f 1 -d ' ' ehbio.fa | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end
  • ctrl+a回到命令的行首,用于修改常命令或注释掉命令
# 写完下面的命令,突然不想运行了,又不想一个个删掉
ct@ehbio:~/ehbio_project$ cut -f 1 -d ' ' ehbio.fa | tail -n 4

# 按ctrl+a, 回到行首,再输入`#`号,回车,命令即被注释掉。
ct@ehbio:~/ehbio_project$ #cut -f 1 -d ' ' ehbio.fa | tail -n 4

  • !! 表示上一条命令。
ct@ehbio:~/ehbio_project$ ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio6.fa  ehbio.fa  second.fa
ct@ehbio:~/ehbio_project$ !!
ls
ehbio3.fa  ehbio4.fa  ehbio5.fa  ehbio6.fa  ehbio.fa  second.fa
  • 替换上一个命令中的字符,再运行一遍命令,用于需要对多个文件执行同样的命令,又不想写循环的情况
# 输入一个命令
ct@ehbio:~/ehbio_project$ #cut -f 1 -d ' ' ehbio.fa | tail -n 4

# !!表示上一条命令
# :gs表示替换,把上一个命令中全部的ehbio替换为ehbio3; g: global; s: substitute
ct@ehbio:~/ehbio_project$ !!:gs/ehbio/ehbio3
#cut -f 1 -d ' ' ehbio3.fa | tail -n 4

# 替换后效果如上

# 去掉命令前的#号
ct@ehbio:~/ehbio_project$ cut -f 1 -d ' ' ehbio3.fa | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

## 替换ehbio3为ehbio4,直接运行命令
ct@ehbio:~/ehbio_project$ !!:gs/ehbio3/ehbio4
cut -f 1 -d ' ' ehbio4.fa | tail -n 4
>mYC
ACGGAGCGAGCTAGTGCAGCGAGGAGCTGAGTCGAGC
CAGGACAGGAGCTA
end

Linux下的标准输入、输出、重定向、管道

在Linux系统中,有4个特殊的符号,<, ‘>’, ‘ ’, ‘-‘,在我们处理输入和输出时存在重要但具有迷惑性的作用。

默认Linux的命令的结果都是输出到标准输出,错误信息 (比如命令未找到或文件格式识别错误等) 输出到标准错误,而标准输出和标准错误默认都会显示到屏幕上。

>表示重定向标准输出,> filename就是把标准输出存储到文件filename里面。标准错误还是会显示在屏幕上。

2 >&1 表示把标准错误重定向到标准输出。Linux终端用2表示标准错误,1表示标准输出。

- (短横线):表示标准输入,一般用于1个程序需要多个输入的时候。

<标准输入,后面可以跟可以产生输出的命令,一般用于1个程序需要多个输入的时候。

|管道符,表示把前一个命令的输出作为后一个命令的输入,前面也有一些展示例子。用于数据在不同的命令之间传输,用途是减少硬盘存取损耗。

下面我们通过一个程序stdout_error.sh来解释上面的文字,内容如下

#!/bin/bash

echo "I am std output" 
# 下面是随便写的一个理论上不存在的命令, 理论上会报错的。
unexisted_command

运行这个脚本

# 标准输出和标准错误默认都会显示到屏幕上
ct@ehbio:~$ bash stdout_error.sh 
I am std output
stdout_error.sh: line 5: unexisted_command: command not found

# >把结果输入到了文件;标准错误还显示在屏幕上
ct@ehbio:~$ bash stdout_error.sh >stdout_error.stdout
stdout_error.sh: line 5: unexisted_command: command not found
ct@ehbio:~$ cat stdout_error.stdout
I am std output

# >把结果输入到了文件; 2>把标准错误输入到了另一个文件
ct@ehbio:~$ bash stdout_error.sh >stdout_error.stdout 2>stdout_error.stderr
ct@ehbio:~$ cat stdout_error.stderr
stdout_error.sh: line 5: unexisted_command: command not found

# 标准输出和标准错误写入同一个文件
ct@ehbio:~$ bash stdout_error.sh >stdout_error.stdout 2>&1
ct@ehbio:~$ cat stdout_error.stdout
I am std output
stdout_error.sh: line 5: unexisted_command: command not found

下面看管道符和标准输入的使用。

# 管道符的使用
# 第一个命令的输出作为第二个的输入
# 前面的例子中也有使用
# tr: 是用于替换字符的,把空格替换为换行,文字就从一行变为了一列
ct@ehbio:~$ echo "1 2 3" | tr ' ' '\n'
1
2
3

# cat命令之前也用过,输出一段文字
# diff是比较2个文件的差异的,需要2个参数
# - (短横线)表示上一个命令的输出,传递给diff
# < 表示其后的命令的输出,也重定向给diff
ct@ehbio:~$ cat <<END | diff - <(echo "1 2 3" | tr ' ' '\n')
> 2
> 3
> 4
> END
0a1
> 1
3d3
< 4

# 如果不使用管道和重定向标准输入,程序是这么写的

# 先把第一部分存储为1个文件
ct@ehbio:~$ cat <<END >firstfile
2
3
> 4
> END
ct@ehbio:~$ less firstfile 

# 再把第二部分存储为1个文件
ct@ehbio:~$ echo "1 2 3" | tr ' ' '\n' >secondfile

# 然后比较
ct@ehbio:~$ diff firstfile secondfile 
0a1
> 1
3d3
< 4

管道符的更多应用

ct@ehbio:~$ echo  "actg aaaaa cccccg" | tr ' ' '\n' | wc -l
3

# sed =:先输出行号,再输出每行的内容
ct@ehbio:~$ echo  "a b c" | tr ' ' '\n' | sed =  
1
a
2
b
3
c

# 后面这个命令不太好解释
# sed = 同时输出行号
# N: 表示读入下一行;sed命令每次只读一行,加上N之后就是缓存了第2行,所有的操作都针对第一行;
# s: 替换;把换行符替换为\t
ct@ehbio:~$ echo  "a b c" | tr ' ' '\n' | sed = | sed 'N;s/\n/\t/' 
1	a
2	b
3	c

# 后面这个命令不太好解释
# sed = 同时输出行号
# N: 表示读入下一行;sed命令每次只读一行,加上N之后就是缓存了第2行,所有的操作都针对第一行;
# s: 替换;把读取的奇数行行首加一个'>'(偶数行相当于被隐藏了)
ct@ehbio:~$ echo  "a b c" | tr ' ' '\n' | sed = | sed 'N;s/^/>/' 
>1
a
>2
b
>3
c

# 把多条序列转成FATSA格式
# sed = 同时输出行号
# N: 表示读入下一行;sed命令每次只读一行,加上N之后就是缓存了第2行,所有的操作都针对第一行;
# s: 替换;把读取的奇数行行首加一个'>'(偶数行相当于被隐藏了)
# 于是FASTA格式序列就出来了
ct@ehbio:~$ echo  "actg aaaaa cccccg" | tr ' ' '\n' | sed = | sed 'N;s/^/>/' 
>1
actg
>2
aaaaa
>3
cccccg

文件的可执行属性和环境变量

Linux下文件有一个特殊的属性即可执行属性,用来指示这个文件是一个可执行的脚本或可以运行的二进制文件。前面所提到的这些命令,都具有可执行属性。

which: 表示查看命令的路径。一般用于当我们想知道使用的命令来源于什么地方时,比如安装了多个R或多个python,但又分不清用的是哪个时,which一下,立即明了。在这儿我们用which获取的是可执行的命令所在的路径,进而查看其属性。

ct@ehbio:~$ ls -l "`which cd`"
#rwx: 文件所有者可读、可写、可执行
#r-x: 文件所有者所在组其它成员可读、可执行,不可修改
#r-x: 其它人可读、可执行,不可修改
-rwxr-xr-x 1 root root 26 12月  7 2016 /usr/bin/cd
ct@ehbio:~$ ls -l "`which mkdir`"
-rwxr-xr-x. 1 root root 79768 11月  6 2016 /usr/bin/mkdir
ct@ehbio:~$ ls -l "`which python`"
#l: 代表软连接
#软连接自身是所有人可读可写,但具体的权限依赖于其链接的文件
lrwxrwxrwx. 1 root root 7 3月  22 15:04 /usr/bin/python -> python2
ct@ehbio:~$ ls -l "`which python2`"
#第二层链接
lrwxrwxrwx. 1 root root 9 3月  22 15:04 /usr/bin/python2 -> python2.7
#链接的原始文件
ct@ehbio:~$ ls -l "`which python2.7`"
-rwxr-xr-x. 1 root root 7136 11月  6 2016 /usr/bin/python2.7

文件属性rwxr表示read (数字表示为4)、w表示write (数字表示为2)、x表示执行 (数字表示为1)。三个未一组,连续出现三次(如下面命令行中所示), 第一组表示文件的所有者拥有的权限,第二组为文件所有者所在的用户组所拥有的权限,组内所有成员都具有的权限,第三组为其它用户的权限。

chmod a+x file: 表示给文件增加所有人(a)可执行权限 (+x)

chmod u+x file: 表示给文件增加所有者(u,user,)可执行权限 (+x)

chmod g+x, chmod o+X: 表示给文件增加组内人或其它人可执行权限

chmod 755 file: 表示拥有者有可读写执行权限,其它人有可读执行权限。(7=4+2+1; 5=4+1)

具体使用man chmod查看其它参数使用。

# 新建个文件
ct@ehbio:~$ cat <<END >run.sh
> echo " I am a script created by ehbio." 
> END

# 查看其权限值
ct@ehbio:~$ ls -l run.sh 
-rw-rw-r-- 1 ct ct 39 6月  14 23:12 run.sh

# 更改权限值
ct@ehbio:~$ chmod 755 run.sh

# 查看其权限值
# 注意多了3个x
ct@ehbio:~$ ls -l run.sh 
-rwxr-xr-x 1 ct ct 39 6月  14 23:12 run.sh

# 去除其它用户的可执行权限
ct@ehbio:~$ chmod o-x run.sh 

# 注意看少了个x
ct@ehbio:~$ ls -l run.sh 
-rwxr-xr-- 1 ct ct 39 6月  14 23:12 run.sh

# 去除同组的可执行权限
ct@ehbio:~$ chmod g-x run.sh

# 注意看又少了个x
ct@ehbio:~$ ls -l run.sh 
-rwxr--r-- 1 ct ct 39 6月  14 23:12 run.sh

# 去除所有人的可执行权限
ct@ehbio:~$ chmod a-x run.sh
ct@ehbio:~$ ls -l run.sh 
-rw-r--r-- 1 ct ct 39 6月  14 23:12 run.sh

# 给所有人增加可执行权限
ct@ehbio:~$ chmod a+x run.sh
ct@ehbio:~$ ls -l run.sh 
-rwxr-xr-x 1 ct ct 39 6月  14 23:12 run.sh

如果一个文件有了可执行权限,是不是就可以执行了,我们来检测下。

ct@ehbio:~$ run.sh
-bash: run.sh: 未找到命令

事实上并非如此,输入命令,回车后,提示命令未找打,这是为什么呢?

这就涉及到环境变量的概念,通俗的讲,环境变量就是告诉电脑 (实际是操作系统)几个目录。这几个目录下存储又可执行文件,如前面显示的/usr/bin目录,大部分的系统命令都在这个目录下。

当我们输入命令mkdir时,系统就会在环境变量所代表的几个目录从前都厚去查找,哪个里面有mkdir文件,然后去执行mkdir命令。

系统中环境变量的名字是PATH,其内容可通过下面的命令显示 (根据操作系统不同和配置不同,略有差别,但格式是统一的,:分割的一堆路径):

ct@ehbio:~$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

所以如果我们想让自己的命令能被系统找到,就需要把命令所在的目录加到环境变量里面,怎么操作呢?

加到环境变量的路径必须是全路径,全路径指以/开头或已~开头的路径。

# 加到环境变量的路径必须是全路径,全路径指以/开头或已~开头的路径
# 注意第一个PATH不含$, 第二个PATH有$符号
# 我们后面会讲什么时候用$, 什么时候不用$
ct@ehbio:~$ export PATH=$PATH:/home/ct
ct@ehbio:~$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/ct

这时,我们在执行那个命令试试,成功运行了。

ct@ehbio:~$ run.sh 
I am a script created by ehbio.

所以在以后安装了新的软件,或者写了新的脚本后,都把软件的可执行程序可执行的脚本所在的目录,加到环境变量里面就可以了。

但是,在命令行中执行export,对环境变量所做的修改,只对当前终端有效,退出后就无效了。为了使得这一操作,长期有效,我们需要把这句话写入一个文件中,一个登陆服务器就会被自动读取的文件中。

对于普通用户,在远程登录终端时,家目录下的~/.bash_profile (不是~/.bashrc, 在本地登录时才会被读取)会自动被读取,所以我们需要把export语句加入到这个文件中。

# 这是我的~/.bash_profile中的内容,主要是最好一行。可以连续的加入多个路径。
if [ -f ~/.bashrc ]; then
	. ~/.bashrc
fi
	
if [ -f ~/.bash_aliases ]; then
	. ~/.bash_aliases
fi
		
export PATH=$PATH:/home/ct:/home/bin:/home/soft/bowtie2/bin

前面提到,系统查找命令的顺序是从环境变量的第一个目录到最后一个目录,在第一次碰到查询的命令后,就调用执行。假如系统存在一个python命令,我们自己又安装了一个python (假如在/home/ct/anaconda/bin目录下),如果我们想执行自己的python程序,就需要把/home/ct/anaconda/bin写在$PATH前面,如下

# 注意$PATH的顺序

ct@ehbio:~$ export PATH=/home/ct/anaconda/bin:$PATH

至此,我们可以熟练使用环境变量来简化命令的输入过程了,因为如果没有环境变量,我们就得需要运行/home/ct/anaconda/bin/python来运行python命令了。

环境变量这块,自己多操作下,就会慢慢理解熟练了。

环境变量的补充

PATH只是众多环境变量中的一个变量,用于存储可执行文件所在的目录,以便在用户输入命令时可以查询的到。尤其是自己写的脚本或安装的程序,系统不会知道它们在哪个路径下,需要我们去提供给系统这些新的路径,学名叫设置环境变量。

此外常用到的环境变量还有LD_LIBARY_PATH: 指定动态链接库 (so文件)的位置,一般在安装软件出错时会用到;PYTHONPATH: 指定Python的安装包的路径;PERL5LIB: 指定perl的安装包的路径。

设置环境变量要注意2点:1. 设置新的环境变量时一般要包含原始的环境变量,不能覆盖;2. 注意自己的目录和系统环境变量的目录的顺序,想让哪个先被找到,就先放哪个。

文件内容操作 (二)

文件排序

seq: 产生一系列的数字; man seq查看其具体使用。我们这使用seq产生下游分析所用到的输入文件。

# 产生从1到10的数,步长为1
ct@ehbio:~$ seq 1 10
1
2
3
4
5
6
7
8
9
10

# 产生从1到10的数,步长为1,用空格分割
ct@ehbio:~$ seq -s ' ' 1 10
1 2 3 4 5 6 7 8 9 10

# 产生从1到10的数,步长为2
# 如果有3个数,中间的数为步长,最后一个始终为最大值
ct@ehbio:~$ seq -s ' ' 1 2 10
1 3 5 7 9

# 还记得前面提到的标准输入和标准输出吧
# 后台回复 标准输入 查看
ct@ehbio:~$ cat <(seq 0 3 17) <(seq 3 6 18) >test
ct@ehbio:~$ cat test 
0
3
6
9
12
15
3
9
15

sort: 排序,默认按字符编码排序。如果想按数字大小排序,需添加-n参数。

# 可能不符合预期的排序,系统首先排0,然后排1, 3, 6, 9
ct@ehbio:~$ sort test
0
12
15
15
3
3
6
9
9
# 按数字大小排序
ct@ehbio:~$ sort -n test
0
3
3
6
9
9
12
15
15

sort -u: 去除重复的行,等同于sort | uniq

ct@ehbio:~$ sort -nu test
0
3
6
9
12
15

sort file | uniq -d: 获得重复的行。(d=duplication)

ct@ehbio:~$ sort -n test | uniq -d
3
9
15

sort file | uniq -c: 获得每行重复的次数。

# 第一列为每行出现的次数,第二列为原始的行
ct@ehbio:~$ sort -n test | uniq -c
  1 0
  2 3
  1 6
  2 9
  1 12
  2 15

# 换一个文件看的更清楚
ct@ehbio:~$ cat <<END >test2
> a
> b
> c
> b
> a
> e
> d
> a
> END

# 第一列为每行出现的次数,第二列为原始的行
ct@ehbio:~$ sort test2 | uniq -c
3 a
2 b
1 c
1 d
1 e

# 在执行uniq操作前,文件要先排序,不然结果很诡异
ct@ehbio:~$ cat test2 | uniq -c
1 a
1 b
1 c
1 b
1 a
1 e
1 d
1 a

整理下uniq -c的结果,使得原始行在前,每行的计数在后。

awk是一个强大的文本处理工具,其处理数据模式为按行处理。每次读入一行,进行操作。OFS: 输出文件的列分隔符 (output file column separtor);FS为输入文件的列分隔符 (默认为空白字符)。awk中的列从第1到n列,分别记录为$1, $2$nBEGIN表示在文件读取前先设置基本参数;与之相对应的是END,只文件读取完成之后进行操作。不以BEGIN, END开头的{}就是文件读取、处理的部分。

# 管道符还记得吧,后台回复 管道 可查看
# awk的操作就是镀金上一步的结果,去除多余的空白,然后调换2列
ct@ehbio:~$ sort test2 | uniq -c | awk 'BEGIN{OFS="\t";}{print $2, $1}'
a	3
b	2
c	1
d	1
e	1

对两列文件,安照第二列进行排序, sort -k2,2n

# 第二列按数值大小排序
ct@ehbio:~$ sort test2 | uniq -c | awk 'BEGIN{OFS="\t";}{print $2, $1}' | sort -k2, 2n
c	1
d	1
e	1
b	2
a	3

# 第二列按数值大小排序
# 第二列相同的再按第一列的字母顺序的逆序排序 (-r)
# 注意看前3行的顺序与上一步结果的差异
ct@ehbio:~$ sort test2 | uniq -c | awk 'BEGIN{OFS="\t";}{print $2,$1}' | sort -k2,2n -k1,1r
e	1
d	1
c	1
b	2
a	3

FASTA序列提取

生成单行序列FASTA文件,提取特定基因的序列,最简单的是使用grep命令。

grep在前面也提到过,以后还会经常提到,主要用途是匹配文件中的字符串,以此为基础,进行一系列的操作。如果会使用正则表达式,将会非常强大。正则表达式版本很多,几乎每种语言都有自己的规则,本文档不会展开,用到哪个提哪个。

# 生成单行序列FASTA文件
ct@ehbio:~$ cat <<END >test.fasta
> >SOX2
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> >POU5F1
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> >NANOG
> CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT
> END
ct@ehbio:~$ cat test.fasta 
>SOX2
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
>POU5F1
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
>NANOG
CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT

# grep匹配含有SOX2的行
# -A 1 表示输出的行中,包含匹配行的下一行 (A: after)
ct@ehbio:~$ grep -A 1 'SOX2' test.fasta 
>SOX2
ACGAGGGACGCATCGGACGACTGCAGGACTGTC

# 也可以使用AWK
# 先判断当前行是不是 > 开头,如果是,表示是序列名字行,替换掉大于号,取出名字。
# sub 替换, sub(被替换的部分,要替换成的,待替换字符串)
# 如果不以大于号开头,则为序列行,存储起来。
# seq[name]: 相当于建一个字典,name为key,序列为值。然后就可以使用name调取序列。
ct@ehbio:~$ awk 'BEGIN{OFS=FS="\t"}{if($0~/>/) {name=$0; sub(">", "", name);} else seq[name]=$0;}END{print ">SOX2"; print seq["SOX2"]}' test.fasta
>SOX2
ACGAGGGACGCATCGGACGACTGCAGGACTGTC

多行FASTA序列提取要麻烦些,一个办法就是转成单行序列,用上面的方式处理。

sedtr都为最常用的字符替换工具。

ct@ehbio:~$ cat <<END >test.fasta
> >SOX2
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> ACGAGGGACGCATCGGACGACTGCAGGAC
> >POU5F1
> CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT
> CGGAAGGTAGTCGTCAGTGCAGCGAGTCC
> >NANOG
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> ACGAGGGACGCATCGGACGACTGCAGG
> ACGAGGGACGCATCGGACGACTGCAGGACTGTC
> ACGAGGGACGCATCGGACGACTGCAGGACTGT
> END

# 给>号开头的行的行尾加个TAB键,以便隔开名字和序列
# TAB键不可见,直接看看不大
# \(\)表示记录匹配的内容,\1则表示()中记录的匹配的内容
# 后面我们专门讲sed
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta 
>SOX2	
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
ACGAGGGACGCATCGGACGACTGCAGGAC
>POU5F1	
CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT
CGGAAGGTAGTCGTCAGTGCAGCGAGTCC
>NANOG	
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
ACGAGGGACGCATCGGACGACTGCAGG
ACGAGGGACGCATCGGACGACTGCAGGACTGTC
ACGAGGGACGCATCGGACGACTGCAGGACTGT

#使用cat -A 可以显示文件中所有的符号
# ^I 表示tab键
# $表示行尾

ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | cat -A
>SOX2^I$
ACGAGGGACGCATCGGACGACTGCAGGACTGTC$
ACGAGGGACGCATCGGACGACTGCAGGACTGTC$
ACGAGGGACGCATCGGACGACTGCAGGAC$
>POU5F1^I$
CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT$
CGGAAGGTAGTCGTCAGTGCAGCGAGTCC$
>NANOG^I$
ACGAGGGACGCATCGGACGACTGCAGGACTGTC$
ACGAGGGACGCATCGGACGACTGCAGG$
ACGAGGGACGCATCGGACGACTGCAGGACTGTC$
ACGAGGGACGCATCGGACGACTGCAGGACTGT$

# 把所有的换行符替换为空格
# tr这个命令,前面提到过,若想不起来 `man tr`查看
# 主意第二个参数,引号内为空格。
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | tr '\n' ' '
>SOX2	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGAC >POU5F1	 CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT CGGAAGGTAGTCGTCAGTGCAGCGAGTCC >NANOG	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGG ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGT 

# 把最后一个空格替换为换行符
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | tr '\n' ' ' | sed -e 's/ $/\n/'
>SOX2	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGAC >POU5F1	 CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT CGGAAGGTAGTCGTCAGTGCAGCGAGTCC >NANOG	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGG ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGT

# 把  ' >'替换为换行符 注意被替换的是 空格+大于号
# 当连用多个替换命令时,使用-e 隔开
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | tr '\n' ' ' | sed -e 's/ $/\n/' -e 's/ >/\n>/g'
>SOX2	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGAC
>POU5F1	 CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGT CGGAAGGTAGTCGTCAGTGCAGCGAGTCC
>NANOG	 ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGG ACGAGGGACGCATCGGACGACTGCAGGACTGTC ACGAGGGACGCATCGGACGACTGCAGGACTGT

# 把所有的空格替换掉
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | tr '\n' ' ' | sed -e 's/ $/\n/' -e 's/ >/\n>/g' -e 's/ //g'
>SOX2	ACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGAC
>POU5F1	CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGTCGGAAGGTAGTCGTCAGTGCAGCGAGTCC
>NANOG	ACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACTGT

# 把TAB键转换为换行符
ct@ehbio:~$ sed 's/^\(>.*\)/\1\t/' test.fasta | tr '\n' ' ' | sed -e 's/ $/\n/' -e 's/ >/\n>/g' -e 's/ //g' -e 's/\t/\n/g' 
>SOX2
ACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGAC
>POU5F1
CGGAAGGTAGTCGTCAGTGCAGCGAGTCCGTCGGAAGGTAGTCGTCAGTGCAGCGAGTCC
>NANOG
ACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACTGT

或者简单点,直接用前面的awk略微做下修改。

# 差别只在一点
# 对于单行fasta文件,只需要记录一行,seq[name]=$0
# 对于多好fasta文件,需要把每一行序列都加到前面的序列上,seq[name]=seq[name]$0
ct@ehbio:~$ awk 'BEGIN{OFS=FS="\t"}{if($0~/>/) {name=$0; sub(">", "", name);} else seq[name]=seq[name]$0;}END{print ">SOX2"; print seq["SOX2"]}' test.fasta
>SOX2
ACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGACTGTCACGAGGGACGCATCGGACGACTGCAGGAC

命令运行监测

  1. 检测命令的运行时间 time command
ct@ehbio:~$ time sleep 5

real	0m5.003s # 程序开始至结束的时间,包括其它进程占用的时间片和IO时间
user	0m0.001s # 进程真正执行占用CPU的时间, 
sys	0m0.002s     # 进程在内核中调用所消耗的CPU时间
user+sys是进程实际的CPU时间。如果多线程执行,这个时间可能大于Real。如果IO是瓶颈,则real会大于user+sys (单线程)。
  1. 查看正在运行的命令和其资源使用 top
  • top输出界面第一行主要信息是负载显示,分别是1分钟、5分钟、15分钟前到现在的任务队列的平均长度。
  • 一般与CPU数目相当为好,过大系统负载超额,反应慢。
  • 在top输出界面输入 u, 会提示输入用户名,以查看某个用户的进程。
  • 重点关注的是%MEM列,查看系统占用的内存是否超出。
ct@ehbio:~$ top -a #按内存排序显示

top - 09:02:11 up 224 days,  8:34,  30 users,  load average: 40, 33, 28
Tasks: 1561 total,   1 running, 1550 sleeping,   0 stopped,  10 zombie
Cpu(s):  0.6%us,  0.2%sy,  0.0%ni, 99.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  2642768880k total, 2094619800k used, 548149080k free,   4310240k buffers
Swap: 86472700k total, 73226016k used, 13246684k free, 193383748k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                  
32527 ct        20   0 2631m 1.7g 1332 S  0.0  0.7 100:34.87 rsem-run-em 
29273 ct        20   0 4094m 692m 3396 S  0.0  0.3  45:18.83 java -Xmx1000m
40148 mysql     20   0 21.9g 606m 6116 S  1.3  0.2   2536:06 /usr/sbin/mysqld
31040 ct        20   0 1887m  77m 2604 S  0.3  0.0 180:43.16 [celeryd: 
  1. 查看系统进程 ps auwx | grep 'process_name'

文件系统和磁盘信息监测

查看系统硬盘大小和分配

ct@ehbio:~$ df -h
Filesystem            Size  Used   Avail   Use% Mounted on
/dev/sda3             193G  112G     71G    62% /
tmpfs                 127G  104K    127G     1% /dev/shm
/dev/sda2             477M  102M    351M    23% /boot
/dev/sda1             200M  264K    200M     1% /boot/efi
/dev/mapper/ehbiobp1  137T   10T    127T     7% /ehbioB
/dev/mapper/ehbiocp1  137T   32T  104.8T    23% /ehbioC
/dev/mapper/ehbiodp1  137T   56T     81T    41% /ehbioD
ct@ehbio:~$ du -sh *
268M	blog
4.0K	browserMimic.py
5.6G	CAFE
386M	chip
73M	class
4.0K	config.file
4.0K	do_not_del_r_test.Rmd
7.2M	ehbio
20K	ehbio_logo.png
12K	ehbio_weixin.jpg
4.0K	Grid_with_line.Rmd
8.0K	heatmap_nonlinear.pdf
8.0K	heatmap_nooutlier.pdf

软件安装

不同于windows,Linux下软件安装的方式比较多样,有些也比较复杂。每种安装方式都有自己的优点和局限,也都有可能遇到问题。在我们理解了原理之后,借助谷歌,可以更好地帮助解决问题。

系统包管理器安装

软件安装最方便的、一般也不容易出问题的是利用系统自带的包管理工具,可以解决大部分的依赖问题。

# centos
# 如果长时间没更新,先运行下update
yum update
# 如果不知道软件具体名字,可以先用一个关键字search一下, 选择正式的名字
# 需要注意的是一般的服务器都是64 bit,需要选x86_64版本
yum search soft_name or soft_description
yum search soft_official_name

但也有一些不足,主要3点:

  1. 需要根用户的权限。
  2. 如果系统版本老,安装的软件版本也会比较老。使用新版本有时又会发生冲突。
  3. 生物信息学中不少软件不在系统的安装源里面。

解决这些问题,就需要自己去软件官网查找最新的分法包,又有两种可能,一种是分法包直接就是编译好的软件,下载下来设置下可执行属性并放入环境变量就可以运行了,如于blastbowtie这样的工具。

另一种则是需要从源码编译安装,下面主要讲解下这个。

源码编译安装

源码编译经典的三部曲configure, make, make install。如果不出问题,对着执行下来就安装好了,也不一定知其所以然。但出了问题,就不是比较容易解决的。如果知道这背后的机制,还是会有帮助的。

  • configure是检查系统的库文件、类文件、依赖软件是否存在以及它们的版本是否满族需求,并根据实际检测结果生成Makefile的工具。一般是一堆bash命令的组合。通常也需要在这一步配置一些参数。最常用的就是指定软件的安装目录--prefix=/home/ct/soft/specific_name

  • make则是具体的编译过程。编译的语句都写在了Makefile中。make默认编译Makefile中出现的第一个target,也可以指定target编译,并根据Makefile的设置方式依次编译所有依赖的东西。

    Makefile通常的格式和布局如下,有兴趣的可以自己去学,或者我们再出一个教程。

    # 假设当前文件夹下Makefile文件中内容如下 
    ct@ehbio:~$ cat Makefile
    # first: target名字
    # echo "compile first": target对应的命令,任何Linux命令都可以
    first:
    	echo "compile first"
    all: first second
    	echo "compile all"
    second:
    	echo "compile second"
      
    # 直接运行make,会make第一个出现的target
    ct@ehbio:~$ make
    echo "compile first"
    compile first
    # make first与直接make相同,因为它出现在第一个 
    ct@ehbio:~$ make first
    echo "compile first"
    compile first
    # all依赖于first, second,因此make all会先执行make first, make second
    # 然后才是自己所代表的命令 
    ct@ehbio:~$ make all
    echo "compile first"
    compile first
    echo "compile second"
    compile second
    echo "compile all"
    compile all
    

有些软件的安装,在执行完make后就获得了可执行程序,可以跳过make install的过程,只需要放入环境变量就可以运行了。但部分软件还需要一些依赖关系,所以需要执行make install才算完成了完整的安装。

  • make install通常是拷贝make编译出来的可执行文件或者依赖的库文件(如果有的话)到configure时的--prefix指定的目录下。

  • 安装好的软件放入环境变量, 就可以快乐的运行了。

两条注意:

  • 从源码编译最难解决的问题就是依赖的库文件、头文件、其它软件的缺失或版本不匹配,没有统一的解决办法,原则就是缺啥补啥

  • 三部曲每一步的执行,屏幕上都会输出比较多的信息,一定仔细看最后有没有ERROR类的字样,对判断软件有无安装成功和下一步要怎么做会很有帮助。

Linux包的安装的通用方式主要这些,后面还会提到两种虚拟安装方式,也都是为了简化安装而提出的。

Python包的安装

在没有Anaconda(或其前身canopy)出现之前,Python包以其管理混乱、安装困难著称。有了Anaconda后,不只python包的安装简单了,其它软件的安装也都方便了 (详见后面Anaconda的两个福利)。

  • 首先下载Anaconda的安装包 https://www.continuum.io/downloads。
  • Anaconda的安装包做的很人性化,一个bash脚本,只要运行bash Anacond*x86_64.sh,然后按照提示操作就可以了。
  • 按照好后,设置或刷新下环境变量就可以使用了。
  • 此后再安装python的包只需要执行pip install pakcage_nameconda install pakckage_name就可以了。
  • 这里唯一需要注意的就是确认使用的pythonpip确实是Anaconda安装的pythonpip
    • which python查看使用的python命令。
    • 如果使用的还是系统默认的python,则需要检查下环境变量的设置。

Anaconda的两个福利

  1. 头文件和库文件库

这是Anaconda安装后的目录结构

bin   envs  Examples  imports  lib    LICENSE.txt  pkgs     share  var
conda-meta  etc   gcc include  lib64  mkspecsplugins  ssl

其中lib目录下,一部分是依赖的动态链接库, .so文件;这也是在源码编译时最常见的拦路虎。通常,只需要把这个目录放入环境变量LD_LIBRARY_PATH里面比如export LD_LIBARY_PATH=${LD_LIBARY_PATH}:anaconda_path/lib就可以解决问题。

cairo                    libitm.a              libQtScript.so.4
cmake                    libitm.la             libQtScript.so.4.8
engines                  libitm.so             libQtScript.so.4.8.7
gcc                      libitm.so.1           libQtScriptTools.la
gcj-4.8.5-14             libitm.so.1.0.0       libQtScriptTools.prl
glib-2.0                 libitm.spec           libQtScriptTools.so
libargtable2.a           libjpeg.a             libQtScriptTools.so.4
libargtable2.la          libjpeg.la            libQtScriptTools.so.4.8
libargtable2.so          libjpeg.so            libQtScriptTools.so.4.8.7
libargtable2.so.0        libjpeg.so.8          libQtSql.la
libargtable2.so.0.1.8    libjpeg.so.8.4.0      libQtSql.prl
libasan.a                libmkl_avx2.so        libQtSql.so
libasan.la               libmkl_avx512_mic.so  libQtSql.so.4
libasan_preinit.o        libmkl_avx512.so      libQtSql.so.4.8
libasan.so               libmkl_avx.so         libQtSql.so.4.8.7
  1. bioconda

bioconda提供了一个虚拟环境,方便软件的编译安装。具体的我没用过,可以读下 徐洲更的生信软件的好帮手-bioconda。

R包的安装

R包的安装具体看之前的R教程。

需要注意的也是依赖的软件或库文件的版本,同样的Anaconda提供的lib库也可以直接拿来用。

备注

文中凡是提到环境变量的地方都可链接到之前提到的环境变量使用的文章,请务必仔细读两遍。

如果软件版本或依赖实在解决不了的,用Docker,虚拟出一个新的系统来解决,具体见。

原文链接 http://blog.genesino.com//2017/06/bash1/

微信公众号

http://mp.weixin.qq.com/s/yKP1Kboji9N4p2Sl1Ovj0Q