Linux的学习--shell,根据某硅谷的一个B站分享学的

shell的语法

因为kaldi使用的是shell脚本

path.sh

export WENET_DIR=$PWD/../../..
export BUILD_DIR=${WENET_DIR}/runtime/libtorch/build
export OPENFST_BIN=${BUILD_DIR}/../fc_base/openfst-build/src
export PATH=$PWD:${BUILD_DIR}/bin:${BUILD_DIR}/kaldi:${OPENFST_BIN}/bin:$PATH

# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C
export PYTHONIOENCODING=UTF-8
export PYTHONPATH=../../../:$PYTHONPATH
# llll

export:这个关键字用来声明一个环境变量,并使它对当前 Shell 进程及其子进程可见。

shell里面的特殊变量

HOME

在Shell脚本中,除了特殊变量之外,还有一些常用的预定义变量,它们在不同的Shell中可能有所不同。以下是一些常见的常变量:

1. **HOME**:当前用户的主目录路径。
2. **USER**:当前用户的用户名。
3. **SHELL**:当前用户的默认Shell路径。
4. **PWD**:当前工作目录的路径。
5. **OLDPWD**:上一个工作目录的路径。
6. **PATH**:系统搜索可执行文件的路径。
7. **LANG**:当前Shell的语言设置。
8. **HOSTNAME**:当前主机的主机名。
9. **OSTYPE**:当前操作系统的类型。
10. **TERM**:当前终端类型。

这些变量可以在Shell脚本中直接使用,也可以通过`echo`命令来查看它们的值。在编写Shell脚本时,可以利用这些常变量来获取系统和用户的信息,以及控制脚本的行为。

Shell 中有一些特殊的变量,它们具有特定的含义和用途。下面是一些常见的特殊变量:

1. **$0**:表示当前脚本或命令的名称。
2. **$1, $2, ..., $n**:表示脚本或命令的参数,其中 `$1` 表示第一个参数,`$2` 表示第二个参数,依此类推。
3. **$@**:表示所有的命令行参数,每个参数作为一个单独的字符串。
4. **$#**:表示命令行参数的个数。
5. **$?**:表示上一个命令的退出状态码。
6. **$$**:表示当前 Shell 进程的进程号。
7. **$!**:表示上一个后台运行的命令的进程号。
8. **$**:表示上一个命令的输出结果。

除了这些,还有一些特殊的变量,用于控制 Shell 的行为,比如 `IFS` 用于设置字段分隔符,`PATH` 用于设置命令搜索路径等等。

当前环境变量有:

export WENET_DIR=$PWD/../../..

export BUILD_DIR=${WENET_DIR}/runtime/libtorch/build

export OPENFST_BIN=${BUILD_DIR}/../fc_base/openfst-build/src

export PATH=$PWD:${BUILD_DIR}/bin:${BUILD_DIR}/kaldi:${OPENFST_BIN}/bin:$PATH

# NOTE(kan-bayashi): Use UTF-8 in Python to avoid UnicodeDecodeError when LC_ALL=C

export PYTHONIOENCODING=UTF-8

export PYTHONPATH=../../../:$PYTHONPATH

export PATH=$PWD:${BUILD_DIR}/bin:${BUILD_DIR}/kaldi:${OPENFST_BIN}/bin:$PATH

这行命令用于将当前目录($PWD)以及指定的几个其他目录添加到系统的PATH环境变量中。这样做的目的是让系统能够在这些目录中查找到可执行文件,而不需要在执行命令时指定完整的路径。

 


查看有几个GPU

# Automatically detect number of gpus
if command -v nvidia-smi &> /dev/null; then
  num_gpus=$(nvidia-smi -L | wc -l)
  gpu_list=$(seq -s, 0 $((num_gpus-1)))
  echo "$gpu_list"
  echo "$num_gpus"
else

  num_gpus=-1
  gpu_list="-1"
fi
nvidia-smi命令用法

`nvidia-smi -L` 命令用于列出系统中所有 NVIDIA GPU 设备的相关信息,包括设备索引、GPU 型号和 UUID。通常的输出格式如下:

```
GPU 0: GeForce GTX 1080 Ti (UUID: GPU-xxxxxxxxxxxxxxxxxxxxxxxxxxxx)
GPU 1: GeForce RTX 2080 (UUID: GPU-xxxxxxxxxxxxxxxxxxxxxxxxxxxx)
```

每行输出代表一个 GPU 设备,包含了设备索引、GPU 型号和 UUID(唯一标识符)。

wc

wc 的英文全称是 "word count",意为单词统计。这个命令在Unix和类Unix系统上被广泛使用,用于统计文件中的行数、字数和字节数。

`wc` 是一个用于统计文件或输入流中字数、行数、字符数等信息的命令。下面是一些常见的 `wc` 命令的用法:

1. 统计文件的行数:
   ```
   wc -l file.txt
   ```

2. 统计文件的字数(单词数):
   ```
   wc -w file.txt
   ```

3. 统计文件的字符数:
   ```
   wc -c file.txt
   ```

4. 同时统计行数、字数和字符数:
   ```
   wc file.txt
   ```

5. 统计输入流(通过管道传递的数据)的行数:
   ```
   cat file.txt | wc -l
   ```

6. 统计多个文件的总行数:
   ```
   wc -l file1.txt file2.txt
   ```

`wc` 命令还有一些其他选项,可以用来灵活地定制输出格式,比如 `-m` 选项用于统计字节数,`-L` 选项用于找出文件中最长行的长度等等。你可以通过 `man wc` 命令查看 `wc` 命令的完整用法和选项。

echo

`echo` 是一个在终端中输出文本的命令,它可以接受一个或多个参数,并将它们原样输出到标准输出(通常是终端窗口)。以下是一些常见的用法:

1. 输出文本字符串:
   ```
   echo "Hello, World!"
   ```

2. 输出变量的值:
   ```
   name="Alice"
   echo "Hello, $name!"
   ```

3. 输出多个参数(用空格分隔):
   ```
   echo "Today is" $(date)
   ```

4. 输出换行符(默认情况下,echo 输出完文本后会自动换行):
   ```
   echo "Line 1"
   echo "Line 2"
   ```

5. 禁用换行符(使用 `-n` 选项):
   ```
   echo -n "Hello, "
   echo "World!"
   ```

6. 输出特殊字符(使用转义字符):
   ```
   echo "This is a \"quoted\" text."
   ```

7. 将文本输出到文件中(使用重定向符 `>`):
   ```
   echo "Hello, World!" > output.txt
   ```

`echo` 命令还有一些其他选项,你可以通过运行 `man echo` 命令来查看完整的用法和选项。

seq

`seq` 是一个用于生成数字序列的命令。它的基本语法如下:

```
seq [选项]... [起始值] [增量] [结束值]
```

其中,`起始值` 表示序列的起始值,默认为1;`增量` 表示序列中相邻两个数字的差值,默认为1;`结束值` 表示序列的结束值。

例如,你可以使用以下命令来生成从1到10的数字序列:

```
seq 1 10
```

如果你希望生成从1到10的偶数序列,可以指定一个步长为2:

```
seq 1 2 10
```

`seq` 还支持一些选项,例如 `-s` 用于指定输出时的分隔符,`-w` 用于指定输出宽度,等等。你可以通过运行 `man seq` 命令来查看完整的用法和选项。

if else fi 结构

`if else fi` 结构是在 Bash 脚本中用来进行条件判断的一种常见语法。它的基本格式如下:

```bash
if [ 条件 ]; then
    # 如果条件为真(非零),则执行这里的代码块
    指令1
    指令2
    ...
else
    # 如果条件为假(零),则执行这里的代码块
    指令3
    指令4
    ...
fi
```

其中:

- `if [ 条件 ]; then`:用于指定条件判断的开始,`[ 条件 ]` 中的条件可以是各种表达式,比如字符串比较、数值比较、文件存在检查等。
- `then`:用于指定条件为真时执行的代码块的开始。
- `else`:可选的部分,用于指定条件为假时执行的代码块的开始。
- `fi`:用于结束 `if else` 结构。

以下是一个示例,演示了如何在 Bash 脚本中使用 `if else fi` 结构:

```bash
#!/bin/bash

# 定义一个变量
age=20

# 判断年龄是否大于等于18
if [ $age -ge 18 ]; then
    echo "你已经成年了"
else
    echo "你还未成年"
fi
```

 在这个示例中,如果年龄大于等于18,则输出 "你已经成年了";否则,输出 "你还未成年"。

cat

`cat` 是 "concatenate" 的缩写,用于连接文件并打印到标准输出设备(通常是终端)。它也可以用于创建新文件、将内容附加到现有文件以及将多个文件合并成一个文件。

`cat` 命令的基本用法是:

```
cat [选项] [文件...]
```

常见的选项包括:

- `-n`:对输出的每一行进行编号。
- `-b`:对输出的非空行进行编号。
- `-E`:在每一行的结尾添加 "$" 符号。
- `-T`:将制表符显示为 "^I"。
- `-v`:显示不可打印字符。

例如,要查看文件 `example.txt` 的内容,可以使用以下命令:

```
cat example.txt
```

这将输出文件 `example.txt` 的内容到标准输出。如果要同时查看多个文件的内容,可以将它们的文件名依次列出即可。

除了查看文件内容外,`cat` 还可以用于将多个文件合并成一个文件。例如,要将文件 `file1.txt` 和 `file2.txt` 合并为一个新文件 `combined.txt`,可以使用以下命令:

```
cat file1.txt file2.txt > combined.txt
```

这将文件 `file1.txt` 和 `file2.txt` 的内容合并,并将结果保存到文件 `combined.txt` 中。

echo

明白了,让我们用中文回答:

- **命令:** `echo`

  **解释:** `echo` 命令的英文全称是 "echo - display a line of text",意为“显示一行文本”。

  **功能:** `echo` 命令用于在终端上显示文本或变量的值。它会将指定的文本或变量输出到标准输出。

 grep

Grep 命令的15种常用用法(值得收藏)_grep用法-CSDN博客


用于指定某个GPU

# You can also manually specify CUDA_VISIBLE_DEVICES
# if you don't want to utilize all available GPU resources.
export CUDA_VISIBLE_DEVICES="${gpu_list}"
echo "CUDA_VISIBLE_DEVICES is ${CUDA_VISIBLE_DEVICES}"


设置参数

stage=0 # start from 0 if you need to start from data preparation
stop_stage=5

# You should change the following two parameters for multiple machine training,
# see https://pytorch.org/docs/stable/elastic/run.html
HOST_NODE_ADDR="localhost:0"
num_nodes=1
job_id=2023

# The aishell dataset location, please change this to your own path
# make sure of using absolute path. DO-NOT-USE relatvie path!
data=/mnt/d/wslstore/dataaishell/
data_url=www.openslr.org/resources/33

nj=12
dict=data/dict/lang_char.txt

# data_type can be `raw` or `shard`. Typically, raw is used for small dataset,
# `shard` is used for large dataset which is over 1k hours, and `shard` is
# faster on reading data and training.
data_type=raw
num_utts_per_shard=1000

train_set=train
# Optional train_config
# 1. conf/train_transformer.yaml: Standard transformer
# 2. conf/train_conformer.yaml: Standard conformer
# 3. conf/train_unified_conformer.yaml: Unified dynamic chunk causal conformer
# 4. conf/train_unified_transformer.yaml: Unified dynamic chunk transformer
# 5. conf/train_u2++_conformer.yaml: U2++ conformer
# 6. conf/train_u2++_transformer.yaml: U2++ transformer
# 7. conf/train_u2++_conformer.yaml: U2++ lite conformer, must load a well
#    trained model, and freeze encoder module, otherwise there will be a
#    autograd error
train_config=conf/train_conformer.yaml
dir=exp/conformer
tensorboard_dir=tensorboard
checkpoint=
num_workers=8
prefetch=500

# use average_checkpoint will get better result
average_checkpoint=true
decode_checkpoint=$dir/final.pt
average_num=30
decode_modes="ctc_greedy_search ctc_prefix_beam_search attention attention_rescoring"

train_engine=torch_ddp

deepspeed_config=conf/ds_stage2.json
deepspeed_save_states="model_only"

. tools/parse_options.sh || exit 1;
参数传递脚本,用于解析参数的脚本
#!/bin/bash

# Copyright 2012  Johns Hopkins University (Author: Daniel Povey);
#                 Arnab Ghoshal, Karel Vesely

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
# WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
# MERCHANTABLITY OR NON-INFRINGEMENT.
# See the Apache 2 License for the specific language governing permissions and
# limitations under the License.


# Parse command-line options.
# To be sourced by another script (as in ". parse_options.sh").
# Option format is: --option-name arg
# and shell variable "option_name" gets set to value "arg."
# The exception is --help, which takes no arguments, but prints the
# $help_message variable (if defined).


###
### The --config file options have lower priority to command line
### options, so we need to import them first...
###

# Now import all the configs specified by command-line, in left-to-right order
for ((argpos=1; argpos<$#; argpos++)); do
  if [ "${!argpos}" == "--config" ]; then
    argpos_plus1=$((argpos+1))
    config=${!argpos_plus1}
    [ ! -r $config ] && echo "$0: missing config '$config'" && exit 1
    . $config  # source the config file.
  fi
done


###
### No we process the command line options
###
while true; do
  [ -z "${1:-}" ] && break;  # break if there are no arguments
  case "$1" in
    # If the enclosing script is called with --help option, print the help
    # message and exit.  Scripts should put help messages in $help_message
    --help|-h) if [ -z "$help_message" ]; then echo "No help found." 1>&2;
      else printf "$help_message\n" 1>&2 ; fi;
      exit 0 ;;
    --*=*) echo "$0: options to scripts must be of the form --name value, got '$1'"
      exit 1 ;;
    # If the first command-line argument begins with "--" (e.g. --foo-bar),
    # then work out the variable name as $name, which will equal "foo_bar".
    --*) name=`echo "$1" | sed s/^--// | sed s/-/_/g`;
      # Next we test whether the variable in question is undefned-- if so it's
      # an invalid option and we die.  Note: $0 evaluates to the name of the
      # enclosing script.
      # The test [ -z ${foo_bar+xxx} ] will return true if the variable foo_bar
      # is undefined.  We then have to wrap this test inside "eval" because
      # foo_bar is itself inside a variable ($name).
      eval '[ -z "${'$name'+xxx}" ]' && echo "$0: invalid option $1" 1>&2 && exit 1;

      oldval="`eval echo \\$$name`";
      # Work out whether we seem to be expecting a Boolean argument.
      if [ "$oldval" == "true" ] || [ "$oldval" == "false" ]; then
        was_bool=true;
      else
        was_bool=false;
      fi

      # Set the variable to the right value-- the escaped quotes make it work if
      # the option had spaces, like --cmd "queue.pl -sync y"
      eval $name=\"$2\";

      # Check that Boolean-valued arguments are really Boolean.
      if $was_bool && [[ "$2" != "true" && "$2" != "false" ]]; then
        echo "$0: expected \"true\" or \"false\": $1 $2" 1>&2
        exit 1;
      fi
      shift 2;
      ;;
  *) break;
  esac
done


# Check for an empty argument to the --cmd option, which can easily occur as a
# result of scripting errors.
[ ! -z "${cmd+xxx}" ] && [ -z "$cmd" ] && echo "$0: empty argument to --cmd option" 1>&2 && exit 1;


true; # so this script returns exit code 0.

第-1步指定文件夹路径,里面没有tgz文件的的话就会下载解压

if [ ${stage} -le -1 ] && [ ${stop_stage} -ge -1 ]; then
  echo "stage -1: Data Download"
  local/download_and_untar.sh ${data} ${data_url} data_aishell
  local/download_and_untar.sh ${data} ${data_url} resource_aishell
fi
 local/download_and_untar.sh
#!/bin/bash

# Copyright   2014  Johns Hopkins University (author: Daniel Povey)
#             2017  Xingyu Na
# Apache 2.0

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

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

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

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.tgz
  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

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;
[条件判断]

在Shell脚本中,常用的条件语句中的逻辑运算符有以下几种:

1. `-eq`:等于
2. `-ne`:不等于
3. `-gt`:大于
4. `-lt`:小于
5. `-ge`:大于等于
6. `-le`:小于等于
7. `-z`:字符串为空
8. `-n`:字符串非空

-f 是一个常用的条件测试选项,用于检查给定的路径是否是一个普通文件。

-d 用于测试路径是否存在且是一个目录

这些逻辑运算符通常用于比较操作符两边的值。比如,`-eq` 用于检查两个数值是否相等,`-z` 用于检查一个字符串是否为空。它们在条件语句中经常用于控制流程,根据条件的真假来执行不同的代码块。


if [ ${stage} -le 0 ] && [ ${stop_stage} -ge 0 ]; then
  # Data preparation
  local/aishell_data_prep.sh ${data}/data_aishell/wav \
    ${data}/data_aishell/transcript
fi
aishell_data_prep.sh
#!/bin/bash

# Copyright 2017 Xingyu Na
# Apache 2.0

. ./path.sh || exit 1;

if [ $# != 2 ]; then
  echo "Usage: $0 <audio-path> <text-path>"
  echo " $0 /export/a05/xna/data/data_aishell/wav /export/a05/xna/data/data_aishell/transcript"
  exit 1;
fi

aishell_audio_dir=$1
aishell_text=$2/aishell_transcript_v0.8.txt

train_dir=data/local/train
dev_dir=data/local/dev
test_dir=data/local/test
tmp_dir=data/local/tmp

mkdir -p $train_dir
mkdir -p $dev_dir
mkdir -p $test_dir
mkdir -p $tmp_dir

# data directory check
if [ ! -d $aishell_audio_dir ] || [ ! -f $aishell_text ]; then
  echo "Error: $0 requires two directory arguments"
  exit 1;
fi

# find wav audio file for train, dev and test resp.
find $aishell_audio_dir -iname "*.wav" > $tmp_dir/wav.flist
n=`cat $tmp_dir/wav.flist | wc -l`
[ $n -ne 141925 ] && \
  echo Warning: expected 141925 data data files, found $n

grep -i "wav/train" $tmp_dir/wav.flist > $train_dir/wav.flist || exit 1;
grep -i "wav/dev" $tmp_dir/wav.flist > $dev_dir/wav.flist || exit 1;
grep -i "wav/test" $tmp_dir/wav.flist > $test_dir/wav.flist || exit 1;
# ...
rm -r $tmp_dir

# Transcriptions preparation
for dir in $train_dir $dev_dir $test_dir; do
  echo Preparing $dir transcriptions
  sed -e 's/\.wav//' $dir/wav.flist | awk -F '/' '{print $NF}' > $dir/utt.list
  paste -d' ' $dir/utt.list $dir/wav.flist > $dir/wav.scp_all
  tools/filter_scp.pl -f 1 $dir/utt.list $aishell_text > $dir/transcripts.txt
  awk '{print $1}' $dir/transcripts.txt > $dir/utt.list
  tools/filter_scp.pl -f 1 $dir/utt.list $dir/wav.scp_all | sort -u > $dir/wav.scp
  sort -u $dir/transcripts.txt > $dir/text
done

mkdir -p data/train data/dev data/test

for f in wav.scp text; do
  cp $train_dir/$f data/train/$f || exit 1;
  cp $dev_dir/$f data/dev/$f || exit 1;
  cp $test_dir/$f data/test/$f || exit 1;
done

echo "$0: AISHELL data preparation succeeded"
exit 0;
find

`find` 是一个用于在指定目录下搜索文件和目录的命令,它提供了丰富的选项和功能。下面是 `find` 命令的基本用法和一些常用选项:

### 基本用法:

```
find <directory> <options>
```

- `<directory>`:指定要搜索的目录。
- `<options>`:可以是一系列选项和搜索条件,用于指定搜索的规则。

### 常用选项:

- `-name pattern`:根据文件名模式搜索文件。例如,`-name "*.txt"` 表示搜索扩展名为 `.txt` 的文件。
- `-iname pattern`:类似于 `-name`,但不区分文件名的大小写。
- `-type type`:根据文件类型搜索,`f` 表示普通文件,`d` 表示目录,`l` 表示符号链接等。
- `-maxdepth level`:限制搜索的最大深度。
- `-mindepth level`:限制搜索的最小深度。
- `-exec command {} +`:对搜索到的文件执行指定的命令。
- `-print`:打印搜索到的文件名。

### 示例:

1. 在当前目录及其子目录中搜索名为 `example.txt` 的文件:
   ```
   find . -name "example.txt"
   ```

2. 在 `/usr/bin` 目录中搜索以 `gcc` 开头的文件:
   ```
   find /usr/bin -name "gcc*"
   ```

3. 在 `/var/log` 目录中搜索所有目录:
   ```
   find /var/log -type d
   ```

4. 在 `/home` 目录中搜索大于100M的文件:
   ```
   find /home -type f -size +100M
   ```

5. 在 `/tmp` 目录中搜索文件并删除:
   ```
   find /tmp -name "*.tmp" -exec rm {} +
   ```

以上是 `find` 命令的基本用法和一些常用选项。通过结合不同的选项,可以实现更复杂和灵活的文件搜索和操作。

find -iname是什么意思

-inamefind 命令的一个选项,用于在搜索文件时忽略文件名的大小写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值