Zhou's home Zhou's home
首页
说话人识别
算法题库
编程相关
语音识别
关于
  • 分类
  • 标签
  • 归档
  • 常用工具
  • 友情链接

ZhouWJ

吾生也有涯,而知也无涯
首页
说话人识别
算法题库
编程相关
语音识别
关于
  • 分类
  • 标签
  • 归档
  • 常用工具
  • 友情链接
  • Kaldi Toolbox

    • Kaldi的基本框架和逻辑
    • 使用预训练Xvector模型进行测试
    • Kaldi中的PLDA自适应
    • Kaldi声纹识别代码详解|egs/aishell
      • stage0 数据准备
        • local/downloadanduntar.sh
        • local/aishelldataprep.sh
      • stage1 提取MFCC
        • steps/make_mfcc.sh
        • sid/computevaddecision.sh
        • utils/fixdatadir.sh
      • stage2 训练UBM
        • sid/traindiagubm.sh
        • sid/trainfullubm.sh
      • stage3 训练ivector提取器
        • sid/trainivectorextractor.sh
      • stage4 提取ivector
        • sid/extract_ivectors.sh
      • stage5 训练PLDA模型
        • ivector-compute-plda
        • ivector-normalize-length
      • stage6 划分注册与测试集
        • local/splitdataenroll_eval.py
        • local/produce_trials.py
      • stage7 提取ivector
        • sid/extract_ivectors.sh
      • stage8 打分并计算EER
        • ivector-plda-scoring
        • compute-eer
      • shell命令整理
        • exit
        • awk
        • 工作流程
        • 示例
        • 内置变量
        • awk编程
        • 常用参数的含义
        • ./与. ./的区别
        • 常用运算符
        • if语句的使用
        • 条件测试类型
        • 条件测试的表达式
        • 整数测试
        • 字符串比较
        • 文件测试
        • if语法结构
        • 条件测试的写法
      • 待整理
    • 源码阅读|Kaldi中的PLDA打分
    • PLDA相关代码详解
    • iVector相关代码详解
    • Voxceleb源码阅读
    • Kaldi相关项目及碎片知识
    • Kaldi中的nnet3
  • 算法原理梳理

  • 文献记录

  • 我的工作

  • 声纹识别
  • Kaldi Toolbox
xugaoyi
2021-02-26
目录

Kaldi声纹识别代码详解|egs/aishell

# stage0 数据准备

data=/export/a05/xna/data # 改为自己存放Data的位置
data_url=www.openslr.org/resources/33

. ./cmd.sh # 设置本地运行/群集
. ./path.sh # 设置需要的路径

set -e # exit on error

# 将$data_url下载到$data/data_aishell文件夹中
local/download_and_untar.sh $data $data_url data_aishell
local/download_and_untar.sh $data $data_url resource_aishell

# Data Preparation
local/aishell_data_prep.sh $data/data_aishell/wav $data/data_aishell/transcript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • set -e

    参考链接:shell脚本中 “set -e” 的作用 (opens new window)

    你写的每个脚本都应该在文件开头加上set -e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出。这样的好处是防止错误像滚雪球般变大导致一个致命的错误,而这些错误本应该在之前就被处理掉。如果要增加可读性,可以使用set -o errexit,它的作用与set -e相同。

# local/download_and_untar.sh

remove_archive=false

# 没有运行这里
if [ "$1" == --remove-archive ]; then
  remove_archive=true
  shift
fi

# 没有运行这里
if [ $# -ne 3 ]; then
  echo "Usage: $0 [--remove-archive] <data-base> <url-base> <corpus-part>"
  echo "e.g.: $0 /export/a05/xna/data www.openslr.org/resources/33 data_aishell"
  echo "With --remove-archive it will remove the archive after successfully un-tarring it."
  echo "<corpus-part> can be one of: data_aishell, resource_aishell."
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • $# -ne 3

    传入的参数总数不等于3

data=$1
url=$2
part=$3

if [ ! -d "$data" ]; then
  echo "$0: no such directory $data"
  exit 1;
fi

part_ok=false
list="data_aishell resource_aishell"
for x in $list; do
  if [ "$part" == $x ]; then part_ok=true; fi
done
# 没有运行这里
if ! $part_ok; then
  echo "$0: expected <corpus-part> to be one of $list, but got '$part'"
  exit 1;
fi
# 检查下载链接是否存在
if [ -z "$url" ]; then
  echo "$0: empty URL base."
  exit 1;
fi

if [ -f $data/$part/.complete ]; then
  echo "$0: data part $part was already successfully extracted, nothing to do."
  exit 0;
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  • 参数说明

    -z:测试指定字符是否为空,空着真,非空为假;

    -f:测试文件是否为普通文件

  • exit 0

    exit命令用于退出当前shell,在shell脚本中可以终止当前脚本执行,如果前面执行成功的话,以0值为返回值退出。

# sizes of the archive files in bytes.
sizes="15582913665 1246920"

# 已经提前下载好,已有tgz压缩文件
if [ -f $data/$part.tgz ]; then
  size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}')
  size_ok=false
  # 检查是否下载完整
  for s in $sizes; do if [ $s == $size ]; then size_ok=true; fi; done
  if ! $size_ok; then
    echo "$0: removing existing file $data/$part.tgz because its size in bytes $size"
    echo "does not equal the size of one of the archives."
    rm $data/$part.gz
  else
    echo "$data/$part.tgz exists and appears to be complete."
  fi
fi

if [ ! -f $data/$part.tgz ]; then
  if ! which wget >/dev/null; then
    echo "$0: wget is not installed."
    exit 1;
  fi
  full_url=$url/$part.tgz
  echo "$0: downloading data from $full_url.  This may take some time, please be patient."
  cd $data
  if ! wget --no-check-certificate $full_url; then
    echo "$0: error executing wget $full_url"
    exit 1;
  fi
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • size=$(/bin/ls -l $data/$part.tgz | awk '{print $5}')

    /bin/ls -l:使用较长格式列出信息

    -rwxrwxrwx 1 zwj zwj 15582913665 4月   1  2019 /media/zwj/数据集/kaldi/data_aishell.tgz
    
    1

    awk '{print $5}':输出第五个域的信息(字节数)

    15582913665
    
    1
cd $data
# 看到这里--------------------------------------------------------------------------------------
if ! tar -xvzf $part.tgz; then
  echo "$0: error un-tarring archive $data/$part.tgz"
  exit 1;
fi

touch $data/$part/.complete

if [ $part == "data_aishell" ]; then
  cd $data/$part/wav
  for wav in ./*.tar.gz; do
    echo "Extracting wav from $wav"
    tar -zxf $wav && rm $wav
  done
fi

echo "$0: Successfully downloaded and un-tarred $data/$part.tgz"

if $remove_archive; then
  echo "$0: removing $data/$part.tgz file since --remove-archive option was supplied."
  rm $data/$part.tgz
fi

exit 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# local/aishell_data_prep.sh

  • 执行local/aishell_data_prep.sh后

只显示到2级目录:

data_aishell ├── transcript │ └── aishell_transcript_v0.8.txt └── wav ├── dev ├── test └── train其他

其中,dev/test/train文件结构一致,内有以spkID命名的文件夹,其中存放对应speaker的wav文件。

# stage1 提取MFCC

mfccdir=mfcc
for x in train test; do
  # $train_cmd即为cmd.sh内设置
  steps/make_mfcc.sh --cmd "$train_cmd" --nj 10 data/$x exp/make_mfcc/$x $mfccdir
  sid/compute_vad_decision.sh --nj 10 --cmd "$train_cmd" data/$x exp/make_mfcc/$x $mfccdir
  utils/fix_data_dir.sh data/$x
done
1
2
3
4
5
6
7

# steps/make_mfcc.sh

这是软链接,链接到/kaldi/egs/wsj/s5/steps

# sid/compute_vad_decision.sh

# utils/fix_data_dir.sh

# stage2 训练UBM

# train diag ubm
sid/train_diag_ubm.sh --nj 10 --cmd "$train_cmd" --num-threads 16 \
  data/train 1024 exp/diag_ubm_1024

#train full ubm
sid/train_full_ubm.sh --nj 10 --cmd "$train_cmd" data/train \
  exp/diag_ubm_1024 exp/full_ubm_1024
1
2
3
4
5
6
7
  • nj,num-threads的含义

# sid/train_diag_ubm.sh

# sid/train_full_ubm.sh

# stage3 训练ivector提取器

sid/train_ivector_extractor.sh --cmd "$train_cmd --mem 10G" \
  --num-iters 5 exp/full_ubm_1024/final.ubm data/train \
  exp/extractor_1024
1
2
3

# sid/train_ivector_extractor.sh

# stage4 提取ivector

sid/extract_ivectors.sh --cmd "$train_cmd" --nj 10 \
  exp/extractor_1024 data/train exp/ivector_train_1024
1
2

# sid/extract_ivectors.sh

# stage5 训练PLDA模型

#train plda
$train_cmd exp/ivector_train_1024/log/plda.log \
  ivector-compute-plda ark:data/train/spk2utt \
  'ark:ivector-normalize-length scp:exp/ivector_train_1024/ivector.scp  ark:- |' \
  exp/ivector_train_1024/plda
1
2
3
4
5

# ivector-compute-plda

# ivector-normalize-length

# stage6 划分注册与测试集

#split the test to enroll and eval
mkdir -p data/test/enroll data/test/eval
cp data/test/{spk2utt,feats.scp,vad.scp} data/test/enroll
cp data/test/{spk2utt,feats.scp,vad.scp} data/test/eval
local/split_data_enroll_eval.py data/test/utt2spk  data/test/enroll/utt2spk  data/test/eval/utt2spk
trials=data/test/aishell_speaker_ver.lst
local/produce_trials.py data/test/eval/utt2spk $trials
utils/fix_data_dir.sh data/test/enroll
utils/fix_data_dir.sh data/test/eval
1
2
3
4
5
6
7
8
9

# local/split_data_enroll_eval.py

# local/produce_trials.py

# stage7 提取ivector

#extract enroll ivector
sid/extract_ivectors.sh --cmd "$train_cmd" --nj 10 \
  exp/extractor_1024 data/test/enroll  exp/ivector_enroll_1024
#extract eval ivector
sid/extract_ivectors.sh --cmd "$train_cmd" --nj 10 \
  exp/extractor_1024 data/test/eval  exp/ivector_eval_1024
1
2
3
4
5
6

# sid/extract_ivectors.sh

# stage8 打分并计算EER

#compute plda score
$train_cmd exp/ivector_eval_1024/log/plda_score.log \
  ivector-plda-scoring --num-utts=ark:exp/ivector_enroll_1024/num_utts.ark \
  exp/ivector_train_1024/plda \
  ark:exp/ivector_enroll_1024/spk_ivector.ark \
  "ark:ivector-normalize-length scp:exp/ivector_eval_1024/ivector.scp ark:- |" \
  "cat '$trials' | awk '{print \\\$2, \\\$1}' |" exp/trials_out

#compute eer
awk '{print $3}' exp/trials_out | paste - $trials | awk '{print $1, $4}' | compute-eer -
1
2
3
4
5
6
7
8
9
10

# ivector-plda-scoring

# compute-eer

# shell命令整理

参考链接:kaldi中文语音识别_基于thchs30(4) - dqxiaoxiao的博客 - CSDN博客 (opens new window)

# exit

同于退出shell,并返回给定值。在shell脚本中可以终止当前脚本执行。执行exit可使shell以指定的状态值退出。若不设置状态值参数,则shell以预设值退出。状态值0代表执行成功,其他值代表执行失败。

  • 检查上一命令脚本的退出码

    ./mycommand.sh
    EXCODE=$?
    if [ "$EXCODE" == "0" ]; then
        echo "O.K"
    fi
    
    1
    2
    3
    4
    5
  • 一些约定

    0表示成功(Zero - Success) 非0表示失败(Non-Zero - Failure) 2表示用法不当(Incorrect Usage) 127表示命令没有找到(Command Not Found) 126表示不是可执行的(Not an executable) >=128 信号产生

  • 在脚本中,进入脚本所在目录,否则退出

    cd $(dirname $0) || exit 1
    
    1

# awk

参考链接:linux awk命令详解 (opens new window)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

awk '{pattern + action}' {filenames}
1

pattern表示 AWK 在数据中查找的内容,而 action是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。pattern就是要表示的正则表达式,用斜杠括起来。

# 工作流程

读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以$1表示登录用户,$3表示登录用户ip,以此类推。

[root@www ~]# last -n 5 <==仅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)
1
2
3
4
5
6

# 示例

  • 改变域分隔符

    awk  -F ':'  '{print $1}'
    
    1
  • 同时输出多个域

    awk  -F ':'  '{print $1"\t"$7}'
    
    1
  • 账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"

    awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
    
    1

    先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

  • 搜索/etc/passwd有root关键字的所有行

    awk -F: '/root/' /etc/passwd
    
    1

# 内置变量

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符
1
2
3
4
5
6
7
8
9
10
11

统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容

awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
1

使用printf替代print,可以让代码更加简洁,易读

awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
1
  • print与printf的区别

    print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

    printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

# awk编程

  • 变量和赋值

    统计/etc/passwd的账户人数:

    awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    ......
    user count is  40
    
    1
    2
    3
    4

    变量初始化是0,但最好先做初始化:

    awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
    [start]user count is  0
    root:x:0:0:root:/root:/bin/bash
    ...
    [end]user count is  40
    
    1
    2
    3
    4
    5

    统计某个文件夹下的文件占用的字节数,统计不包括文件夹的子目录:

    ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
    [end]size is  8657198
    
    1
    2

    字节数以M为单位:

    ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
    [end]size is  8.25889 M
    
    1
    2
  • 条件语句

    if (expression) { # 单分支
        statement;
        statement;
        ... ...
    }
    
    if (expression) { # 双分支
        statement;
    } else {
        statement2;
    }
    
    if (expression) { # 多分支
        statement1;
    } else if (expression1) {
        statement2;
    } else {
        statement3;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹):

    ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}' 
    [end]size is  8.22339 M
    
    1
    2
  • 循环语句

    支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同

  • 数组

    awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。

    显示/etc/passwd的账户:

    awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
    0 root
    1 daemon
    2 bin
    3 sys
    4 sync
    5 games
    ......
    
    1
    2
    3
    4
    5
    6
    7
    8

# 常用参数的含义

$0 就是当前shell脚本本身的名字;

$1 是你给你写的shell脚本传的第一个参数;

$2 是你给你写的shell脚本传的第二个参数;

**$# **表示提供到shell脚本或者函数的参数总数;

**$?**是shell变量,表示"最后一次执行命令"的退出状态,0为成功,非0为失败。

# ./与. ./的区别

参考链接:linux里面的命令:./和. /(这里有空格)的区别 (opens new window)

./: 当前目录(相对路径的写法)

. /:有空格的点号等同于source命令,表示在当前shell环境执行后面的命令或脚本(不加点号默认是新开一个shell执行的)

例如 :/home/test.sh等同于 source /home/test.sh。

source:用source执行的脚本所做的任何改变会影响当前shell(如,其中如果用cd改变了目录,脚本执行完毕后,shell的目录就变了);如果没用source,就不会影响当前shell。

# 常用运算符

参考链接:shell 中 && || () {} 用法 (opens new window)

  • 逻辑与:&&

    &&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行;换句话说,“如果这个命令执行成功&&那么执行这个命令”。

    command1 && command2 && command3 ...
    
    1
  • 逻辑或:||

    ||则与&&相反,如果||左边的命令(command1)未执行成功,那么就执行||右边的命令(command2);或者换句话说,“如果这个命令执行失败了||那么就执行这个命令,实现短路逻辑或操作。

    如果 dir目录不存在,将输出提示信息 fail :

    ls dir &>/dev/null || echo "fail"
    
    1

    如果 dir目录存在,将输出提示信息 success,否则输出fail:

    ls dir &>/dev/null && echo "success" || echo "fail"
    
    1

    常用||组合示例:

    echo $BASH |grep -q 'bash' || { exec bash "$0" "$@" || exit 1; }
    
    1

    系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。

  • 当前shell组合执行:()

    如果希望把几个命令合在一起执行,shell提供了两种方法。既可以在当前shell也可以在子shell中执行一组命令。

    (command1;command2;command3....)               多个命令之间用;分隔
    
    1

    () 表示在当前 shell 中将多个命令作为一个整体执行。需要注意的是,使用 () 括起来的命令在执行前面都不会切换当前工作目录,也就是说命令组合都是在当前工作目录下被执行的,尽管命令中有切换目录的命令。

    如果目录dir不存在,则执行组合命令:

    ls dir &>/dev/null || (cd /home/;ls -1h;echo "success")
    
    1
  • 子shell组合执行:{}

    相应的命令将在子shell而不是当前shell中作为一个整体被执行,只有在{}中所有命令的输出作为一个整体被重定向时,其中的命令才被放到子shell中执行,否则在当前shell执行。

    { command1;command2;command3… }      注意:在使用{}时,{}与命令之间必须使用一个空格
    
    1

    在子shell中执行打印操作

    A=1;echo $A;{ A=2; };echo $A # 得到1 2
    A=1;echo $A;( A=2; );echo $A # 得到1 1
    
    1
    2
  • 管道符号:|

    参考链接:[shell]shell 中| && || () {} 用法以及shell的逻辑与或非 (opens new window)

    command 1 | command 2 
    
    1

    把第一个命令command 1执行的结果作为command2的输入传给command 2,列出当前目录中的文档(含size),并把输出送给sort命令作为输入,sort命令按数字递减的顺序把ls的输出排序。

    ls -s | sort -nr
    
    1

    -s表示file size,-n表示numeric-sort,-r表示reverse,反转

  • 运算级优先级表

    由高级至低级

# if语句的使用

参考链接:shell 学习之if语句 (opens new window)

# 条件测试类型

整数测试、字符测试、文件测试;

# 条件测试的表达式

[ expression ]: 括号两端必须要有空格 [[ expression ]] :括号两端必须要有空格 test expression 组合测试条件: -a: and -o: or !: 非

# 整数测试

-eq 等于,如:if ["$a" -eq "$b" ] -ne 不等于,如:if ["$a" -ne "$b" ] -gt 大于,如:if ["$a" -gt "$b" ] -ge 大于等于,如:if ["$a" -ge "$b" ] -lt 小于,如:if ["$a" -lt "$b" ] -le 小于等于,如:if ["$a" -le "$b" ] < 小于(需要双括号),如:(("$a" < "$b")) <= 小于等于(需要双括号),如:(("$a" <= "$b")) >大于(需要双括号),如:(("$a" >"$b")) >= 大于等于(需要双括号),如:(("$a" >= "$b"))

# 字符串比较

== 等于 两边要有空格 != 不等 > 大于 < 小于`

# 文件测试

-z string:测试指定字符是否为空,空着真,非空为假; -n string:测试指定字符串是否为不空,空为假 非空为真; -e file:测试文件是否存在; -f file: 测试文件是否为普通文件; -d file:测试指定路径是否为目录; -r file:测试文件对当前用户是否可读; -w file:测试文件对当前用户是否可写; -x file :测试文件对当前用户是都可执行; -z :是否为空 为空则为真; -a:是否不空;

# if语法结构

  • 单分支
if 判断条件;then
statement1
statement2
.......
fi
1
2
3
4
5
  • 双分支
if 判断条件;then
statement1
statement2
.....
else
statement3
statement4
fi
1
2
3
4
5
6
7
8
  • 注意点

    if语句进行判断是否为空:[ "$name” = "" ]等同于[ ! "$name" ]或[ -z "$name" ];

    使用if语句的时候进行判断如果是进行数值类的 ,建议使用 let(())进行判断,(())中变量是可以不使用$来引用的;

    对于字符串等使用test[ ] or[[ ]]进行判断;

# 条件测试的写法

  • 执行一个命令的结果:if grep -q "rm" fs.sh;then
  • 传回一个命令执行结果的相反值 :if !grep -q "rm" fs.sh;then
  • 使用复合命令((算式)):if ((a>b));then
  • 使用bash关键字 [[判断式]]:if [[ str > xyz ]];then
  • 使用内置命令:test 判断式:if test "str" \> "xyz";then
  • 使用内置命令:[判断式] 类似test:if [ "str" \> "xyz" ];then
  • 使用-a -o进行逻辑组合:[ -r filename -a -x filename ]
  • 命令&&命令
  • 命令||命令:if grep -q "rm" fn.sh || [ $a -lt 100 ];then

# 待整理

  • 中断程序而不关闭终端

    参考链接:Linux在终端启动程序关闭终端不退出的方法 (opens new window)

    nohup 命令 &:如nohup ./studio.sh &

  • terminator的技巧

    将terminator设为默认终端;

    在别的窗口打开它后,按住红色窄条可以拖到已有的多终端集成窗口;

    在空白处右键即可配置首选项,比如皮肤更换等;

  • 查看文件夹树形结构

    tree:sudo apt-get install tree

    常用格式:tree [option] [directory]

    常用参数[option]:

    • -a:显示所有文件及目录

    • -d:只显示目录

    • -l:如遇到符号链接的目录,直接列出所指向的目录结构

    • -f:在每个文件前显示完整的路径

    • -L level:限制目录显示层级

      只查看第一级的目录和文件

      $ tree -L 1
      
      1

      把目录结构信息保存到文本中

      $ tree -L 2 > /home/php-note.com/tree.txt
      
      1
    • -I:忽略目录下的文件夹或目录

    [directory]:tree 命令作用于哪个目录下,默认当前目录。

  • Sublime Text的侧边栏隐藏快捷键

    默认方式:先按ctrl+k,再按ctrl+b

    自定义:依次打开Preferences—Key Bingings,搜索toggle_side_bar,可以看到系统的定义,我自定义为ctrl+b,与firefox一致

    [
    	{ "keys": ["ctrl+b"], "command": "toggle_side_bar" },
    ]
    
    1
    2
    3
  • Sublime Text中打开软链接:右键——Reveal Link Source

#Kaldi
上次更新: 2024/04/10, 22:12:29
Kaldi中的PLDA自适应
源码阅读|Kaldi中的PLDA打分

← Kaldi中的PLDA自适应 源码阅读|Kaldi中的PLDA打分→

最近更新
01
方言语音识别综述
04-05
02
主流ASR模型概述
03-26
03
一些参考图表及表述
05-28
更多文章>
Theme by Vdoing | Copyright © 2019-2024 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式