前言

在Ubuntu的shell命令行中,当输入字符后,按两次Tab键,shell会列出一输入字符打头的所有可用命令,如果匹配的命令只有一个时,按一次Tab键就自动将该命令补齐。

除了命令补全之外,还有路径、文件名、目录名补全,比如使用cd切换到指定的目录和ls查看指定的文件的时候,都是比较好用的。

介绍

一般ubuntu的终端都会提供自动补全的功能,但是不同的终端略有不同,有些系统一装机就使用的是zsh,但是比较老一点的系统用的是bash,SHELL之间的切换可以使用下列命令:

chsh -s /bin/bash

chsh -s /bin/zsh

## 可以查看/bin下的SHELL类型,在切换到自己喜欢的

ls /bin/*sh

在这里主要介绍bash提供的补全功能。另外,当大家使用命令的时候,后面接参数,这个其实也可以进行补全,只要编辑好合适的补全脚本并存入到目录/etc/bash_completion.d下即可。

对于bash来说,使用的是内置的complete命令,用于支持Tab键的自动补全:

type -a complete

complete is a shell builtin

在Ubuntu中,系统会默认安装bash-completion包,其中包含了常用命令的大部分自动补齐脚本,如果想编写其他命令的补全脚本的时候,可以参考目录/etc/bash_completion.d下的文件的内容。

samtools 补齐

作为生信用的比较多的一个软件之一,自动补齐是比较方便的一个操作,所以一般都会提前配置好,如下:

sudo vi /etc/bash_completion.d/samtools

# From https://raw.github.com/arq5x/bash_completion/master/samtools revision e931a8b46d9582672cc506e45ad9b4f4d6fbd743

_samtools()

{

local cur prev opts

COMPREPLY=()

cur="${COMP_WORDS[COMP_CWORD]}"

prev="${COMP_WORDS[COMP_CWORD-1]}"

opts="dict faidx index calmd fixmate

reheader targetcut addreplacerg

markdup collate cat merge mpileup

sort split quickcheck fastq fasta

bedcov depth flagstat idxstats

phase stats flags tview view depad"

case $prev in

samtools)

COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )

;;

esac

return 0

}

complete -F _samtools -o default samtools

添加完以后保存,执行一下. /usr/share/bash-completion/bash_completion,使修改生效;就可以进行测试了,输入samtools vi,在按Tab键,就会自动补齐成samtools view这样的命令,相对比较方便。

git补齐

用的相对多的另外一个命令应该是git,先从git github上把配置好的文件下载下来:

wget https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash

sudo mv git-completion.bash /etc/bash_completion.d/

接下来在个人账号下面配置环境变量文件~/.bashrc,在其中添加如下语句,每次终端启动就会自动加载配置:

if [ -f /etc/bash_completion.d/git-completion.bash ]; then

. /etc/bash_completion.d/git-completion.bash

fi

执行一次. ~/.bashrc,就可以测试git配置是否生效,git cl之后按Tab键,就会自动出来git clone,再在后面git clone --,再按Tab键,就会出现可选的参数等等。

其他程序

针对前面的samtools,我就依样画葫芦,添加了bwa和sambamba两个程序的complete补全脚本:

BWA 补全

sudo vi /etc/bash_completion.d/bwa

_bwa()

{

local cur prev opts

COMPREPLY=()

cur="${COMP_WORDS[COMP_CWORD]}"

prev="${COMP_WORDS[COMP_CWORD-1]}"

opts="index aln samse sampe

bwasw fastmap mem fa2pac pac2bwt

pac2bwtgen bwtupdate

bwt2sa"

case $prev in

bwa)

COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )

;;

esac

return 0

}

complete -F _bwa -o default bwa

sambamba补全

sudo vi /etc/bash_completion.d/sambamba

_sambamba()

{

local cur=${COMP_WORDS[COMP_CWORD]}

local subcommand=${COMP_WORDS[1]}

if [[ $COMP_CWORD == 1 ]]; then

COMPREPLY=( $(compgen -W "view index merge sort \

flagstat slice markdup \

depth mpileup validate \

subsample" -- $cur) )

compopt +o nospace

elif [[ $cur == -* ]]; then

case "$subcommand" in

view)

COMPREPLY=( $(compgen -W "-F -f -h -H -I -c -S -p \

-l -o -t -s --filter= --header \

--format= --with-header --count \

--reference-info --show-progress \

--sam-input --output-filename= \

--nthreads= --compression-level= \

--subsample= --subsampling-seed=" -- $cur) )

;;

index)

COMPREPLY=( $(compgen -W "-p -t --nthreads= --show-progress" -- $cur) )

;;

merge)

COMPREPLY=( $(compgen -W "-p -t --nthreads= -l -H --header \

--compression-level=" -- $cur) )

;;

sort)

COMPREPLY=( $(compgen -W "-m --memory-limit= --tmpdir= -o --out \

-n --compression-level= -u -p -t \

--uncompressed-chunks --show-progress \

--nthreads=" -- $cur) )

;;

flagstat)

COMPREPLY=( $(compgen -W "-t -p --nthreads= --show-progress" -- $cur) )

;;

slice)

COMPREPLY=( $(compgen -W "-o --output-filename=" -- $cur) )

;;

markdup)

COMPREPLY=( $(compgen -W "-r -t -l -p --tmpdir= --remove-duplicates \

--nthreads= --compression-level= \

--show-progress" -- $cur) )

;;

subsample)

COMPREPLY=( $(compgen -W "--type --max-cov -o --output -r --remove" -- $cur) )

;;

depth)

COMPREPLY=( $(compgen -W "-F -o -t -c -C -q -a -m -L -z -L -T -w -T --filter --output-file --nthreads --min-coverage --max-coverage --min-base-quality --annotate --fix-mate-overlaps --regions --report-zero-coverage --cov-threshold --window-size --cov-threshold" -- $cur) )

;;

mpileup)

COMPREPLY=( $(compgen -W "-L --regions -o --output-filename --tmpdir -t --nthreads -b --buffer-size -B --output-buffer-size" -- $cur) )

;;

esac

if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then

compopt +o nospace

fi

elif [[ ${COMP_WORDS[COMP_CWORD - 2]} == "--format" || ${COMP_WORDS[COMP_CWORD - 1]} == "-f" ]]; then

COMPREPLY=( $(compgen -W "sam bam json msgpack" -- $cur) )

compopt +o nospace

elif [[ $subcommand == "view" || $subcommand == "slice" ]]; then

for word in ${COMP_WORDS[@]}; do

if [[ $word == *.bam && $word != "" ]]; then

eval abspath=$word

COMPREPLY=( $(sambamba view -H -t4 $abspath | grep @SQ | \

cut -f 2 | cut -f2 -d: 2>/dev/null | grep "^$cur") )

break

fi

done

if [[ ${#COMPREPLY[@]} == 0 ]]; then

compopt +o nospace

fi

compopt -o default

compopt -o filenames

else

compopt +o nospace

compopt -o default

fi

}

complete -o nospace -F _sambamba sambamba

在这里修改一下~/.bashrc文件,使得终端启动就可以使用这些自动补全:

vi ~/.bashrc

# enable programmable completion features (you don't need to enable

# this, if it's already enabled in /etc/bash.bashrc and /etc/profile

# sources /etc/bash.bashrc).

if [ -f /etc/bash_completion ] && ! shopt -oq posix; then

. /etc/bash_completion

fi

重新source一下~/.bashrc以后就可以了加载更新的配置了。

常用命令

在上面的这写例子中,使用的是三个shell函数:complete、compgen和compopt,下面介绍一下这三个函数。

complete

complete是补全命令中最核心的命令,指定如何对各个名称进行补全。列出一些常用的参数:

-F function 执行 shell 函数,函数中生成COMPREPLY作为候选的补全结果

-C command 将 command 命令的执行结果作为候选的补全 结果

-G pattern 将匹配 pattern的文件名作为候选的补全结果

-W wordlist 分割 wordlist 中的单词,作为候选的补全结果

-p [name] 列出当前所有的补全命令

-r [name] 删除某个补全命令

-D [name] 其后的选项和动作应用到默认补全,之前未定义的补全命令被补全

可以通过-o设置一些选项,常用的有:

bashdefault 如果没有生成补全条目,就使用bash默认的其它补全

default 如果没有生成补全条目,就使用“readline”默认的文件名补全

nospace 默认会自动填充一个空格,可以通过该参数关闭

filenames 在补全的时候会具体到文件,而不是目录,对于文件补齐比较有用

dirnames 如果没有生成补全条目,就进行目录名补全

noquote 告诉“readline”不引用文件名,默认会进行引用

plusdirs 生成补全条目之后,还会进行目录名补全并把结果添加到其它动作得到的结果中

部分例子:

$ complete -W 'com1 com2 com3 lunar' testm

$ testm

com1 com2 com3 lunar

$ complete -p | grep testm

complete -W 'com1 com2 com3 lunar' testm

$ complete -r testm

$ complete -p | grep testm

compgen

筛选命令,用来筛选生成匹配单词的候选补全结果,根据option生成与word可能匹配的补全:

compgen [option] [word]

## 单词匹配

$ compgen -W 'com1 com2 com3 lunar' -- c

com1

com2

com3

## 匹配当前路径下的文件名和目录名

$ compgen -f -- R

R

README.kegg

compopt

compopt命令修改每个名称指定的补全选项,如果没有指定名称则修改当前执行的补全的选项,如果也没有指定选项,则显示每个名称或当前补全所用的选项。选项可能的取值就是上面的内建命令complete的有效选项。

compopt [-o option] [-DE] [+o option] [name]

+o option 启用 option 配置

-o option 弃用 option 配置

补全变量

在sambamba的补全脚本中,还使用了一些shell内置的补全变量,介绍一下:

COMP_WORDS 数组 存放当前命令行中输入的所有单词

COMP_CWORD 整数 当前输入的单词在 COMP_WORDS 中的索引

COMPREPLY 数组 候选的补全结果

COMP_LINE 字符串 当前的命令行输入字符

COMP_POINT 整数 光标在当前命令行的哪个位置

GATK自动补全

GATK的Tool太多了,每次都不一定能很好的找到,在gatk的目录下面发现了一个好东西:

ls /home/luna/Desktop/Software/gatk/gatk-4.1.8.1/gatk-completion.sh

echo "source /home/luna/Desktop/Software/gatk/gatk-4.1.8.1/gatk-completion.sh" >> ~/.bashrc

稍微测试了一下,还是比较好用的,就是太卡了,应该是我服务器负载太高的原因,大家可以测试一下,虽然这个功能还是处于Beta阶段。

参考

—— dulunar 后记于 2020.07

Logo

更多推荐