第四期书生大模型实战营 - 入门岛闯关作业1 - Linux基础知识

160 阅读13分钟

项目地址
算力平台
课程文档

1. InternStudio开发机介绍


  • InternStudio 是大模型时代下的云端算力平台。基于 InternLM 组织下的诸多算法库支持,为开发者提供开箱即用的大语言模型微调环境、工具、数据集,并完美兼容 🤗 HugginFace 开源生态。

1.1 创建开发机

image.png

image.png

1.2 开发机介绍

  • 开发机有三种模式可以选择:JupyterLab终端VScode

2. SSH及端口映射

2.1 定义

  • SSH全称Secure Shell,中文翻译为安全外壳.

  • SSH 是(C/S架构)由服务器客户端组成.

    1. 建立 TCP 连接
    2. 协商使用的版本号和各类算法
    3. 并生成相同的会话密钥用于后续的对称加密。
    4. 完成用户认证
    5. 双方建立会话进行数据交互。

配置SSH密钥,可以使得我们远程连接开发机时不用重复的输入密码 通过SSH远程连接开发机,可以在本地进行开发。 而且如果你需要跑一些本地的代码,又没有环境,那么远程连接就非常有必要了。

2.2 使用SSH

2.2.1 使用powershell执行开发机配置中的登陆命令和密码,实现开发机连接

image.png

image.png

2.2.2 常用指令

image.png

2.2.3 配置SSH密钥

  • ssh-keygen支持RSA和DSA两种认证密钥。

  • 常用参数包括:

    • -t:指定密钥类型,如dsa、ecdsa、ed25519、rsa。
    • -b:指定密钥长度。
    • -C:添加注释。
    • -f:指定保存密钥的文件名。
    • -i:读取未加密的ssh-v2兼容的私钥/公钥文件。
ssh-keygen -t rsa
  • key path: windows的默认路径就是C:\Users\{your_username}\
    • windows在powerShell中可以使用Get-Content命令查看生成的密钥
    • linux操作系统可以使用cat命令。
  • 将获取到的密钥设置到ssh公钥管理中即可.

image.png

2.2.4 VS Code 远程连接

  • 安装Remote SSH插件

image.png

2.3 端口映射

ssh -p 45929 root@ssh.intern-ai.org.cn -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null

image.png

2.3.1 介绍一下命令各部分的含义:

  • -p 45929:是指定 SSH 连接的端口为 45929,这个前面提到过。

  • root@ssh.intern-ai.org.cn:表示要以 root 用户身份连接到 ssh.intern-ai.org.cn 这个主机。

  • -CNg

    • -C 通常用于启用压缩。
    • -N 表示不执行远程命令,仅建立连接用于端口转发等。
    • -g 允许远程主机连接到本地转发的端口。
  • -L {本地机器_PORT}:127.0.0.1:{开发机_PORT}:这是设置本地端口转发,将本地机器的指定端口(由 {本地机器_PORT} 表示)转发到远程主机(这里即 ssh.intern-ai.org.cn)的 127.0.0.1 (即本地回环地址)和指定的开发机端口(由 {开发机_PORT} 表示)。

  • -o StrictHostKeyChecking=no:关闭严格的主机密钥检查,这样可以避免第一次连接时因为未知主机密钥而产生的提示或错误。

2.3.1 开发机运行python脚本

Prepare: pip install gradio==4.29.0

  • 通过powershell执行上述端口映射实现远程访问开发机
import socket
import re
import gradio as gr
 
# 获取主机名
def get_hostname():
    hostname = socket.gethostname()
    match = re.search(r'-(\d+)$', hostname)
    name = match.group(1)
    
    return name
 
# 创建 Gradio 界面
with gr.Blocks(gr.themes.Soft()) as demo:
    html_code = f"""
            <p align="center">
            <a href="https://intern-ai.org.cn/home">
                <img src="https://intern-ai.org.cn/assets/headerLogo-4ea34f23.svg" alt="Logo" width="20%" style="border-radius: 5px;">
            </a>
            </p>
            <h1 style="text-align: center;">☁️ Welcome {get_hostname()} user, welcome to the ShuSheng LLM Practical Camp Course!</h1>
            <h2 style="text-align: center;">😀 Let’s go on a journey through ShuSheng Island together.</h2>
            <p align="center">
                <a href="https://github.com/InternLM/Tutorial/blob/camp3">
                    <img src="https://oss.lingkongstudy.com.cn/blog/202410081252022.png" alt="Logo" width="50%" style="border-radius: 5px;">
                </a>
            </p>

            """
    gr.Markdown(html_code)

demo.launch()

image.png

3 Linux 基础命令

这一部分我会带着大家了解Linux的一些基础操作,还有使用一些工具。让大家能够在遇到问题的时候,可以自行解决,如果大家有遇到什么问题的话,也可以在这里评论,我会及时给大家回答。

因为我们使用开发机时很少使用到权限管理,所以我们就不介绍了。(后面的操作均在VScode的终端中进行)

3.1 文件管理

在 Linux 中,常见的文件管理操作包括:

  • 创建文件:可以使用 touch 命令创建空文件。
  • 创建目录:使用 mkdir 命令。
  • 目录切换:使用cd命令。
  • 显示所在目录:使用pwd命令。
  • 查看文件内容:如使用 cat 直接显示文件全部内容,more 和 less 可以分页查看。
    • -a,--show-all等价于-vET
    • -b,--number-non空白数非空输出行,覆盖-n
    • -e, 等价于-vE
    • -E,--show-结束显示$在每一行的末尾
    • -n,--number编号所有输出行
    • -s,--crick-空白抑制重复的空输出行
    • -t等价于-vT
    • -t,--show-tabs将制表符显示为^I
    • -v,--show非打印使用^和M-表示法,LFD和TAB除外
  • 编辑文件:如 vi 或 vim 等编辑器。
  • 复制文件:用 cp 命令。
  • 创建文件链接:用ln命令。
  • 移动文件:通过 mv 命令。
  • 删除文件:使用 rm 命令。
  • 删除目录rmdir(只能删除空目录)或 rm -r(可删除非空目录)。
  • 查找文件:可以用 find 命令。
  • 查看文件或目录的详细信息:使用ls命令,如使用 ls -l查看目录下文件的详细信息。
  • 处理文件:进行复杂的文件操作,可以使用sed命令。

image.png

进入编辑模式可以使用i,vim的方便之处就是可以在终端进行简单的文件修改。

image.png

3.1.1 cp 和 ln

  • cp将一个文件或者目录复制到另一个目录下的操作:
    • 复制文件:cp 源文件 目标文件
    • 复制目录:cp -r 源目录 目标目录

使用模型时,这种操作会占用大量的磁盘空间. 所以我们一般使用ln命令,这个就和windows的快捷方式一样。

  • linux中链接分为两种 : 硬链接(hard link)与软链接(symbolic link)

    • 硬链接的意思是一个档案可以有多个名称
    • 软链接的方式则是产生一个特殊的档案,该档案的内容是指向另一个档案的位置。
    • 硬链接是存在同一个文件系统中,而软链接却可以跨越不同的文件系统。
  • 我们一般使用软连接,它的常用的使用方法如下:

ln [参数][源文件或目录][目标文件或目录]

参数如下:
-s:创建软链接(符号链接)也是最常用的;
-f:强制执行,覆盖已存在的目标文件;
-i:交互模式,文件存在则提示用户是否覆盖;
-n:把符号链接视为一般目录;
-v:显示详细的处理过程。

image.png

3.1.2 mv 和 rm

  • mv命令和rm命令的使用方式很相似

  • mv是用来移动文件或者目录的,同时还可以进行重命名。

  • rm命令则是用来删除文件或者目录的。

  • mv常用的使用方法如下:

mv 命令:
-i:交互模式,覆盖前询问。
-f:强制覆盖。
-u:只在源文件比目标文件新时才进行移动。

使用示例: mv file1.txt dir1/:将文件 file1.txt 移动到目录 dir1 中。 mv file1.txt file2.txt:将文件 file1.txt 重命名为 file2.txt。

rm 命令:
-i:交互模式,删除前询问。
-f:强制删除,忽略不存在的文件,不提示确认。
-r:递归删除目录及其内容。

使用示例: rm file.txt:删除文件 file.txt。 rm -r dir1/:递归删除目录 dir1 及其所有内容。 删除目录的命令也可以使用rmdir。

image.png

3.1.3 find

  • 以下是find命令的一些常见用法:
    • 按文件名查找:使用-name选项按照文件名查找文件。例如,find /path/to/directory -name "file.txt"将在指定目录及其子目录中查找名为file.txt的文件。
    • 按文件类型查找:使用-type选项按照文件类型查找文件。例如,find /path/to/directory -type f将查找指定目录及其子目录中的所有普通文件。
    • 按文件大小查找:使用-size选项按照文件大小查找文件。例如,find /path/to/directory -size +100M将查找指定目录及其子目录中大于100MB的文件。
    • 按修改时间查找:使用-mtime、-atime或-ctime选项按照文件的修改时间、访问时间或状态更改时间查找文件。例如,find /path/to/directory -mtime -7将查找指定目录及其子目录中在7天内修改过的文件。
    • 按文件权限查找:使用-perm选项按照文件权限查找文件。例如,find /path/to/directory -perm 755将查找指定目录及其子目录中权限为755的文件。
    • 按用户或组查找:使用-user或-group选项按照文件的所有者或所属组查找文件。例如,find /path/to/directory -user username将查找指定目录及其子目录中属于用户username的文件。
    • 执行操作:使用-exec选项可以对找到的文件执行相应的操作。例如,find /path/to/directory -name "*.txt" -exec rm {} ;将删除找到的所有以.txt结尾的文件。

image.png

3.1.4 ls

ls命令可以用来列出目录的内容以及详细信息。

  • 常用参数及使用方法如下:
    • -a:显示所有文件和目录,包括隐藏文件(以.开头的文件或目录)。
    • -l:以长格式显示详细信息,包括文件权限、所有者、大小、修改时间等。
    • -h:与-l结合使用,以人类可读的方式显示文件大小(如K、M、G等)。
    • -R:递归列出子目录的内容。
    • -t:按文件修改时间排序显示。

image.png

3.1.5 sed

  • sed命令是一种流编辑器

    • 用于文本处理
    • 在处理复杂的文件操作时经常用到
  • sed命令常用参数及使用示例如下:

  • 参数说明

    • -e
    • -f<script文件> 或 --file=<script文件>:从指定的脚本文件中读取脚本进行文本处理。
    • -n 或 --quiet 或 --silent:仅打印经过脚本处理后的输出结果,不打印未匹配的行。
  • 动作说明:

    • a:在当前行的下一行添加指定的文本字符串。
    • c:用指定的文本字符串替换指定范围内的行。
    • d:删除指定的行。
    • i:在当前行的上一行添加指定的文本字符串。
    • p:打印经过选择的行。通常与 -n 参数一起使用,只打印匹配的行。
    • s:使用正则表达式进行文本替换。例如,s/old/new/g 将所有 "InternLM" 替换为 "InternLM yyds"。

echo命令,和python中的print一样,用来打印内容

常用的管道符还有<|

grep是一个强大的文本搜索工具。常用参数如下:
-i:忽略大小写进行搜索。
-v:反转匹配,即显示不匹配的行。
-n:显示行号。
-c:统计匹配的行数。

3.2 进程管理

  • 常用的进程管理命令有以下几种:
    • ps:查看正在运行的进程
      • ps aux显示系统所有进程的详细信息
    • top:动态显示正在运行的进程, 会实时更新进程列表
    • pstree:树状查看正在运行的进程
    • pgrep:用于查找进程,根据进程名、用户等条件查找进程
    • nice:更改进程的优先级,nice值越低,进程优先级越高
    • jobs:显示进程的相关信息,包括后台运行的进程
    • bg 和 fg:将进程调入后台
      • bg: 将最近一个挂起的作业放到后台运行
      • fg: 将后台作业调到前台运行
    • kill:杀死进程
      • kill PID杀死指定的进程ID
      • kill -9 PID 强制杀死进程

3.2.1 nvidia-smi 命令的一些基本命令用法:

  • nvidia-smi: 显示 GPU 状态的摘要信息:
  • nvidia-smi -l 1: 显示详细的 GPU 状态信息:
    • 1表示会每1秒更新一次状态信息。
  • nvidia-smi -h: 显示 GPU 的帮助信息:
  • nvidia-smi pmon: 列出所有 GPU 并显示它们的 PID 和进程名称:
  • nvidia-smi --id=0 --ex_pid=12345: 强制结束指定的 GPU 进程:
    • 这会强制结束 GPU ID 为 0 上的 PID 为 12345 的进程。
  • nvidia-smi -pm 1: 设置 GPU 性能模式, 为所有 GPU 设置为性能模式
  • nvidia-smi -i 0 -pm 1: 只针对 ID 为 0 的 GPU设置为性能模式
  • nvidia-smi --id=0 -r: 重启 GPU: nvidia-smi --id=0 -r: 这会重启 ID 为 0 的 GPU。

3.3 TMUX

Tmux 使用教程

  • TMUX是一个终端多路复用器。
  • 可以在多个终端之间轻松切换
  • 分离它们(这不会杀死终端,它们继续在后台运行)
  • 将它们重新连接到其他终端中。

为什么要介绍这个工具呢?因为在后面进行Xtuner微调模型的时候,时间会很长
使用Tmux可以解决程序被杀死中断的情况。

  • 使用lsb_release -a命令查看ubuntu的系统信息:

使用apt install tmux命令安装tmux
退出tmux可以使用Ctrl+d快捷键。

开发机仅 /root 路径下的文件是持久化存储的,其他路径下安装的软件重启后都会被重置。

4. Conda和Shell介绍

4.1 Conda设置

  • 设置国内镜像提升安装速度,示例如下:
#设置清华镜像
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2

4.2 Conda环境

4.2.1 创建虚拟环境

  • 我们可以使用conda create创建虚拟环境
  • 创建后,可以在.conda目录下的envs目录下找到。
  • -n 或 --name:指定要创建的环境名称。
  • -c 或 --channel:指定额外的软件包通道。
  • --clone:从现有的环境克隆来创建新环境。
  • -p 或 --prefix:指定环境的安装路径(非默认位置)。
# myenv为env name
# 指定路径一般已同时指定name
# 指定python版本(一般不推荐)
conda create --prefix /root/envs/myenv python=3.9

4.2.2 查看有哪些虚拟环境

  • conda env list
  • conda info -e
  • conda info --envs

4.2.3 激活虚拟环境

  • 使用conda activate name命令来激活虚拟环境
    • 看(base)是否变成了创建的虚拟环境的名称。
  • 使用conda activate或者conda deactivate退出虚拟环境
    • 因为base是conda的基础环境,
    • base环境目录比其他的虚拟环境目录层级要高

image.png

4.2.4 删除与导出虚拟环境

  • 删除某个虚拟环境可以使用conda remove --name name --all
  • 只删除虚拟环境中的某个或者某些包可以使用conda remove --name name package_name
  • 导出虚拟环境可导出复杂的依赖关系,这样下次使用还原就行了,而且也可以把配置分享给其他人
#获得环境中的所有配置
conda env export --name myenv > myenv.yml
#重新还原环境
conda env create -f  myenv.yml

4.3 studio-conda使用与Shell

  • studio-conda,这是开发机内置的一个命令,它通过Shell脚本来实现的。 studio-conda就属于自动化的一部分,在我们开发机中root用户的bash环境的配置文件是.bashrc,但其实主要的配置文件是/share/.aide/config/bashrc,在这个文件里面写了一些命令,可以让我们更快捷的执行一些操作.

修改.bashrc文件后执行. ~/.bashrc使其生效

#! /bin/bash

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, don't overwrite it
shopt -s histappend

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar

# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;
esac

# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes

if [ -n "$force_color_prompt" ]; then
    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
	# We have color support; assume it's compliant with Ecma-48
	# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
	# a case would tend to support setf rather than setaf.)
	color_prompt=yes
    else
	color_prompt=
    fi
fi

if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #alias dir='dir --color=auto'
    #alias vdir='vdir --color=auto'

    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi

# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'

# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Add an "alert" alias for long running commands.  Use like so:
#   sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

# 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 ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/root/.conda/condabin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/root/.conda/etc/profile.d/conda.sh" ]; then
        . "/root/.conda/etc/profile.d/conda.sh"
    else
        export PATH="/root/.conda/condabin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

if [ -d "/root/.conda/envs/xtuner" ]; then
  CONDA_ENV=xtuner
else
  CONDA_ENV=base
fi

source activate $CONDA_ENV

if [[ $START_AS_TEAM ]] && (( $START_AS_TEAM == "1" )); then
    cat /share/.aide/config/welcome_team | envsubst
else
    cat /share/.aide/config/welcome_vgpu  
fi

#if [ $CONDA_ENV != "xtuner" ]; then
#  echo -e """
#  \033[31m 检测到您尚未初始化xtuner环境, 建议执行> source init_xtuner_env.sh \033[0m
#  """
#fi
export https_proxy=http://proxy.intern-ai.org.cn:50000
export http_proxy=http://proxy.intern-ai.org.cn:50000
export no_proxy='localhost,127.0.0.1,0.0.0.0,172.18.47.140'
export PATH=/root/.local/bin:$PATH
export HF_ENDPOINT='https://hf-mirror.com'
alias studio-conda="/share/install_conda_env.sh"
alias studio-smi="/share/studio-smi"    

4.3.1 将自己创建的环境添加到studio-conda中(默认方法)

  1. conda create -p /share/conda_envs/xxx python=3.1x
  2. cp -r -n /root/.conda/pkgs/* /share/pkgs/
  3. cd /share && tar -zcvf pkgs.tar.gz pkgs

image.png

4.3.2 clone()

  • 核心逻辑:
    • tar --skip-old-files -xzvf /share/pkgs.tar.gz -C ${CONDA_HOME}
    • conda create -n $target --clone ${SHARE_CONDA_HOME}/${source}
clone() {
    source=$1
    target=$2

    if [[ -z "$source" || -z "$target" ]]; then
        echo -e "\033[31m 输入不符合规范 \033[0m"
        help
        exit 1
    fi

    if [ ! -d "${SHARE_CONDA_HOME}/$source" ]; then
        echo -e "\033[34m 指定的预设环境: $source不存在\033[0m"
        list
        exit 1
    fi

    if [ -d "${CONDA_HOME}/envs/$target" ]; then
        echo -e "\033[34m 指定conda环境的目录: ${CONDA_HOME}/envs/$target已存在, 将清空原目录安装 \033[0m"
        wait_echo&
        wait_pid=$!
        rm -rf "${CONDA_HOME}/envs/$target"
        kill $wait_pid
    fi

    echo -e "\033[34m [1/2] 开始安装conda环境: <$target>. \033[0m"
    sleep 3
    tar --skip-old-files -xzvf /share/pkgs.tar.gz -C ${CONDA_HOME}
    wait_echo&
    wait_pid=$!
    conda create -n $target --clone ${SHARE_CONDA_HOME}/${source}
    if [ $? -ne 0 ]; then
        echo -e "\033[31m 初始化conda环境: ${target}失败 \033[0m"
        exit 10
    fi

    kill $wait_pid

    # for xtuner, re-install dependencies
    case "$source" in
    xtuner)
        source_install_xtuner $target
        ;;
    esac

    echo -e "\033[34m [2/2] 同步当前conda环境至jupyterlab kernel \033[0m"
    lab add $target
    source $CONDA_HOME/bin/activate $target
    cd $HOME_DIR

    echo -e "\033[32m conda环境: $target安装成功! \033[0m"

    echo """
    ============================================
                    ALL DONE!
    ============================================
    """
}

4.3.3 将自己创建的环境添加到studio-conda中(备份还原法)

  • 使用conda导出过xtuner0.1.17虚拟环境的配置文件,我们可以使用conda env create -f xtuner0.1.17.yml命令来还原虚拟环境
#!/bin/bash

# 定义导出环境的函数
export_env() {
    local env_name=$1
    echo "正在导出环境: $env_name"
    # 导出环境到当前目录下的env_name.yml文件
    conda env export -n "$env_name" > "$env_name.yml"
    echo "环境导出完成。"
}

# 定义还原环境的函数
restore_env() {
    local env_name=$1
    echo "正在还原环境: $env_name"
    # 从当前目录下的env_name.yml文件还原环境
    conda env create -n "$env_name" -f "$env_name.yml"
    echo "环境还原完成。"
}

# 检查是否有足够的参数
if [ $# -ne 2 ]; then
    echo "使用方法: $0 <操作> <环境名>"
    echo "操作可以是 'export' 或 'restore'"
    exit 1
fi

# 根据参数执行操作
case "$1" in
    export)
        export_env "$2"
        ;;
    restore)
        restore_env "$2"
        ;;
    *)
        echo "未知操作: $1"
        exit 1
        ;;
esac 

image.png

image.png