Bash 脚本教程

Bash 基础语法

  • 定义变量(变量名和等号之间不能有空格)

a=10

Bash 数组

  • 定义数组

array=(1 2 3)
  • 以命令返回结果定义数组

files=( $(ls) )
  • 获得数组中的某个元素

a=${array[0]}
  • 获得数组的长度

length=${#array[@]}

Bash 运算

  • 自增

c=$((++c))
  • 加法

b=$[$a+1]

Bash 判断语句

单中括号

  • 判断大小

[ $COMP_CWORD -ge 7 ]

双中括号 (注意两侧空格)

  • 正则匹配(变量)

[[ "$pre" =~ "-h" ]]
  • 取反(不是!~

[[ ! "$pre" =~ "-h" ]]
  • 正则匹配(数组)

[[ "${COMP_WORDS[@]}" =~ "-s" ]]
  • 逻辑判断

[[ "${COMP_WORDS[@]}" =~ "-s" || "${COMP_WORDS[@]}" =~ "--sequential" ]]

Bash 循环语句

  • for 循环

for (( i=0; i<${#array[@]}; i++ ))
do
    echo ${array[i]}
done
  • while 循环

while [ $c -lt $COMP_CWORD ]
do
    c=$((++c))
done

Bash 变量替换

使用下述命令可以实现字符串的变量替换:

${string/substring/replacement} # 替换第一个匹配项
${string//substring/replacement} # 替换全部匹配项

具体效果如下所示:

EXEC=/opt/vasp/bin/vasp_std
${EXEC/vasp_std/vasp_gam} => /opt/vasp/bin/vasp_gam

Note

当省略第二个 / 时,将会把匹配到的字符串从变量中删除

例如,我们有一个变量 user

user=root:x:0:0:root:/root:/bin/bash

使用下述命令会发生字符串的删除;

> ${user/r*t}
> :/bin/bash
> ${user//r\*t}
> :/bin/bash
> ${user//r??t}
> :x:0:0::/:/bin/bash
> ${user/r??t}
> :x:0:0:root:/root:/bin/bash

Bash 字符串删除

假设我们定义了一个变量 file

file=/dir1/dir2/dir3/my.file.txt

我们可用 ${var#}/${var%} 来进行字符串删除获得不同的值:

> ${file#_/}
> dir1/dir2/dir3/my.file.txt

> ${file##_/}
> my.file.txt

> ${file#\*.}        
> file.txt

> ${file##_.}        
> txt

> ${file%/_}        
> /dir1/dir2/dir3

> ${file%%/\*}        
> (空值)

> ${file%.\_}
> /dir1/dir2/dir3/my.file

> ${file%%.\_}        
> /dir1/dir2/dir3/my

Bash 函数

  • 将 ls 的结果放到 files 数组中

_files () {
    local c=0
    for file in `ls`
    do
        files[$c]=$file
        c=$((++c))
    done
    echo ${files[@]}
}
  • 获取函数的返回值

files=( $(_files) )

mkdir 命令

  • 构建多级目录 (-p 参数)

mkdir -p /opt/intel/oneapi/**

find 命令

  • 通过管道传送多个命令 (显示指明 bash -c)

find DIR -iname '*.gro' -exec bash -c 'echo -n "{} "; grep UNL {} | wc -l' \;
  • 查找重复文件

find -not -empty -type f -printf "%s\n" | sort -rn | uniq -d | xargs -I{} -n1 find -type f -size {}c -print0 | xargs -0 md5sum | sort | uniq -w32 --all-repeated=separate

xargs 命令

  • 参数替换(-I 选项)

ls | shuf -n 50 | xargs -I {} cp {} DIR

其中,shuf 命令随机选择 N 个文件

awk 命令

  • 条件语句

awk -F, '{if($5>2000){print $0}}' file

sort 命令

  • 先将第一列倒排,再将第三列以数值格式倒排

sort -k 1,1r -k 3,3nr content

grep 命令

  • 多行匹配时去掉分组符号”-”

grep -A2 pattern --no-group-separator

Linux 自定义命令补全

实现 Linux 系统下自定义命令的补全需要借助 bash-completion,它是对 bash 补全功能的增强,可以实现对参数和包名的补全。

默认安装位置在 /etc/bash_completion (/usr/share/bash-completion/completions则是一些工具的补全实现,可作为参考),如果没有安装,可以借助 apt 工具进行安装。

apt install bash-completion

自动补全脚本编写

实现自定义命令的补全主要借助两个命令(completecompgen)以及几个环境变量(COMPREPLYCOMP_WORDSCOMP_CWORD),下面对他们的一些用法进行说明。

complete 命令

  • 用自定义函数(_gvasp)对自定义命令(gvasp)进行补全

complete -F _gvasp gvasp
  • 取消自动添加空格

complete -o -F _gvasp gvasp

compgen 命令

  • 对 cur 字符串从 opts 中进行补全

compgen -W "$opts" -- $cur
  • 当未找到匹配项时,以 bash 自带的补全进行替换

compgen -o default -W "$opts" -- $cur

重要环境变量

  • COMP_CWORD 表示当前光标所在的索引

  • COMP_WORDS 当前命令行所有单词组成的数组

  • COMPREPLY 从该数组变量中产生后续的命令补全

简单实现

_gvasp_submit() {
    local cur opts

    COMPREPLY=()
    pre=${COMP_WORDS[COMP_CWORD-1]}
    cur=${COMP_WORDS[COMP_CWORD]}
    if [[ "$pre" =~ "-" ]]; then
        opts=""
    else
        opts="opt con-TS chg wf dos freq md stm neb dimer -h --help"
    fi
    COMPREPLY=( $( compgen -W "$opts" -- $cur ) )
}

定义好的 bash-completion 脚本在 ~/.bashrc 中定义并通过 source 命令执行即可。

参考资料