记录一下我在服务器上鼓捣了什么。

家目录下的目录结构

家目录~/home/username,主要包含

  • ~/software 目前把第三方软件都安装在这里
    • 按照每个软件分配次级目录 ,例如~/software/git就是 git 的安装位置
    • ~/software/tmp 把软件的压缩包以及解压后的文件夹放置于此,因为服务器不能连接外网,压缩包通过 ftp 传入。
  • ~/scripts 存放一些常用的脚本文件(添加到PATH
  • ~/pbshome 存放PBS作业提交时的快照
  • ~/tmp 存放一些临时文件

配置文件

因为安装软件往往需要设置环境变量,因此在原本的.bashrc脚本最后加上一行,用 source 命令加载自己的.my_bashrc脚本:

1
source ~/.my_bashrc

把频繁修改的内容写在这个.my_bashrc脚本中,把原本的.bashrc以及其他内容都在 Onedrive 上进行了备份。

例如当前(2024-6-05)的.my_bashrc内容如下

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
32
33
34
35
36
# here is my own shell profile

# git version 2.34.8
export GIT_HOME=~/software/git
export PATH=$GIT_HOME/bin:$PATH

# cmake version 3.24.2
export CMAKE_HOME=~/software/cmake
export PATH=$CMAKE_HOME/bin:$PATH

# tmux
export TMUX_HOME=~/software/tmux
export PATH=$TMUX_HOME:$PATH
export TERMINFO=~/software/tmux_depend/ncurses/lib/terminfo

# fish
export FISH_HOME=~/software/fish/bin
export PATH=$FISH_HOME:$PATH

# gcc
# export PATH=~/software/gcc/usr/local/bin:$PATH
export MY_CC=~/software/gcc/usr/local/bin/gcc
export MY_CXX=~/software/gcc/usr/local/bin/g++

#use "-wl,-rpath=$MY_RPATH" for cmake and linker
export MY_RPATH=~/software/gcc/usr/local/lib/gcc/x86_64-pc-linux-gnu/11.2.0:~/software/gcc/usr/local/lib64

# ninja
export NINJA_HOME=~/software/ninja/bin
export PATH=$NINJA_HOME:$PATH

# matlab
export PATH=$PATH:/opt/software/MATLAB/R2015b/bin

# scripts
export PATH=~/scripts:$PATH

这里有一个重要的部分就是多版本gcc共存导致的运行时路径问题,最终没有使用修改环境变量 LD_LIBRARY_PATH 的方法,而是定义了环境变量MY_RPATH,使用 cmake 编译时,自动加入-Wl,-rpath=相应选项,确保基于 cmake 和高版本 gcc 编译的程序可以找到正确的动态库,对 gcc 版本敏感的动态库主要有两个:libstdc++.so.6libgcc_s.so.1,对于二进制程序可以使用 ldd 查看使用的对应动态库。

注意:

  • vscode remote 的环境变量加载逻辑不一样,remote server 不会因为窗口关闭而关闭,服务进程会持续存在,无法及时基于.bashrc等进行更新,需要彻底重启 vscode-server 服务,可以执行命令Kill VS Code Server on Host,参考VSCode Remote环境变量加载
  • 可以考虑加上stty -ixon,避免 tmux 分屏时的终端假死现象,参考这篇博客,但是加上后别的地方也会出现问题,故移除。

软件安装

因为普通用户没有 root 用户权限,服务器还不联网,不能使用傻瓜式的安装,只能在用户家目录下使用源码编译的方式,非常硬核地安装软件,比较复杂,网上教程也不太好找。

git

安装过程主要参考这篇博客

  1. 在官网或者 github 的 git 仓库下载 git-2.34.8.tar.gz(默认 git 只有 1.8,版本太老了)
  2. ftp 传到~/software/tmp目录下,解压tar -zxvf git-2.34.8.tar.gz,得到~/software/tmp/git-2.34.8子目录
  3. 切换到软件安装目录~/software,建立安装目录~/software/git
  4. 进入~/software/tmp/git-2.34.8子目录,make allmake install走起,需要指定安装目录
1
2
make all
make prefix=/home/username/software/git install
  1. 安装完成,接下来把需要的路径添加到 PATH,这里我们在.my_bashrc中实现
1
2
3
# git version 2.34.8
export GIT_HOME=~/software/git
export PATH=$GIT_HOME/bin:$PATH

最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下

1
2
git --version
which git

使用git之前还需进行必要的配置,我们只关注安装过程,因此略去。

cmake

安装过程主要参考这篇博客

  1. 在官网下载 cmake-3.24.2.tar.gz(默认 cmake 只有 2.8.12,版本有点低)
  2. ftp 传到~/software/tmp目录下,解压tar -zxvf cmake-3.24.2.tar.gz,得到~/software/tmp/cmake-3.24.2子目录
  3. 切换到软件安装目录~/software,建立安装目录~/software/cmake
  4. 进入~/software/tmp/cmake-3.24.2子目录,
    1. 执行 ./bootstrap,好像是引导之类的作用
    2. 执行 configure 命令,指定安装目录 ./configure --prefix=/home/username/software/cmake
    3. make allmake install走起,上一步已经指定了安装目录
1
2
3
4
./bootstrap
./configure --prefix=/home/username/software/cmake
make all
make install
  1. 安装完成,接下来把需要的路径添加到 PATH,这里我们在.my_bashrc中实现
1
2
3
# cmake version 3.24.2
export CMAKE_HOME=~/software/cmake
export PATH=$CMAKE_HOME/bin:$PATH

最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下

1
2
cmake --version
which cmake

gcc

gcc 的非 root 用户离线编译安装比其他的软件的源码安装都要复杂:因为它有依赖,无法通过联网下载,要提前下载依赖的压缩包,并且它的编译时间长达好几个小时。

安装过程主要参考这篇博客另一篇博客

  1. 先在官网或者镜像网站下载 gcc-11.2.0.tar.gz(默认 gcc 版本 4.8.5,太老了)
  2. ftp 传到~/software/tmp目录下,解压tar -zxvf gcc-11.2.0.tar.bz,得到~/software/tmp/gcc-11.2.0子目录
  3. 进入~/software/tmp/gcc-11.2.0子目录,下载依赖
    1. 有网络时,直接执行自带的下载依赖的脚本 ./contrib/download_prerequisites
    2. 无网络时,vim 查看上述脚本,找到需要的 gmp,mpfr,mpc,isl 四个依赖的具体版本,在脚本中提供的链接里下载对应的压缩包,用 ftp 传到~/software/tmp/gcc-11.2.0目录之下,例如 gcc-11.2.0 需要的四个依赖版本及其下载地址如下
1
2
3
4
5
6
gmp='gmp-6.1.0.tar.bz2'
mpfr='mpfr-3.1.6.tar.bz2'
mpc='mpc-1.0.3.tar.gz'
isl='isl-0.18.tar.bz2'

base_url='http://gcc.gnu.org/pub/gcc/infrastructure/'
  1. 无网络时,把脚本中下载命令对应的行删除,然后再执行这个脚本 ./contrib/download_prerequisites,因为脚本在下载压缩包之后好像还干了别的事
  2. 返回上一层,在~/software/tmp下建立编译目录~/software/tmp/gcc-11.2.0-build,进入这个子目录
  3. 在编译目录中,执行 configure 命令,命令如下
1
../gcc-11.2.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
  1. 在编译目录中,执行编译命令: make (编译过程非常漫长,可能四五个小时,并且不断有信息输出到控制台)
  2. 切换到软件安装目录~/software,建立安装目录~/software/gcc
  3. 在编译目录中,执行安装命令,注意需要使用 DESTDIR 选项指定安装位置,命令如下
1
make DESTDIR=/home/username/software/gcc install
  1. 安装完成,接下来把需要的路径添加到 PATH,才能让高版本 gcc 发挥作用,但是因为两个版本共存的现状无法改变,没有进行任何环境变量的设置。

在没有版本冲突等问题时,需要修改下面的环境变量来完成gcc的安装。

最基本的可以把 gcc 本身的路径加入 PATH

1
2
# gcc version 11.2.0
export PATH=~/software/gcc/usr/local/bin:~/software/gcc/usr/local/lib64:$PATH

为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,可以测试一下,找到正确的高版本 gcc

1
2
gcc -v
which gcc

(但是这会影响低版本gcc的使用,我关掉了)

如果这个傻缺的 cmake 找不到高版本的 gcc,总是用默认的 gcc,可以在这里指定一下

1
2
export CC=~/software/gcc/usr/local/bin/gcc
export CXX=~/software/gcc/usr/local/bin/g++

为了避免对make等的额外影响,可以改成

1
2
export MY_CC=~/software/gcc/usr/local/bin/gcc
export MY_CXX=~/software/gcc/usr/local/bin/g++

此时cmake可以如下使用

1
cmake -S . -B build -DCMAKE_C_COMPILER=$MY_CC -DCMAKE_CXX_COMPILER=$MY_CXX

同时还需要通过-wl,-rpath=$MY_RPATH修改程序优先查找的动态库,对应在配置文件中的定义

1
export MY_RPATH=~/software/gcc/usr/local/lib/gcc/x86_64-pc-linux-gnu/11.2.0:~/software/gcc/usr/local/lib64

根据第二篇参考博客,还需要添加一些环境变量(在 PATH 设置之后),比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# gcc/g++等程序本身的路径
export PATH=$PATH:/install/bin
# 注:/install为安装目录,下同

# gcc头文件路径
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/install/include

# g++头文件路径
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/install/include

# 动态链接库路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/install/lib64
export LD_LIBRARY_PATH=/path/to/software/gcc9/lib/:$LD_LIBRARY_PATH

# 静态库路径
export LIBRARY_PATH=$LIBRARY_PATH:/install/lib

但是针对当前的系统,我现在并没有设置这些,只是记录一下。

tmux

tmux 是一个 terminal multiplexer(终端复用器),它可以启动一系列终端会话。 它的主要作用是解绑了会话和终端窗口:关闭终端窗口再打开,会话并不终止,而是继续运行在执行,将会话与终端窗后彻底分离。

系统自带了一个 tmux,不过版本只有 1.8 看着有点低,顺手装一个更新版的。安装过程主要参考这篇博客

  1. 在官网下载 tmux 和它的依赖 libevent,ncurses,这里通过 ftp 实现
1
2
3
wget -c https://github.com/tmux/tmux/releases/download/3.0a/tmux-3.0a.tar.gz
wget -c https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stable.tar.gz
wget -c https://ftp.gnu.org/gnu/ncurses/ncurses-6.2.tar.gz
  1. ftp 传到~/software/tmp目录下,解压三个包,得到~/software/tmp/tmux-3.0a等三个子目录
1
2
3
tar -zxvf tmux-3.0a.tar.gz
tar -zxvf libevent-2.1.11-stable.tar.gz
tar -zxvf ncurses-6.2.tar.gz
  1. 切换到软件安装目录~/software,建立 tmux 依赖的安装目录~/software/tmux_depend/libevent~/software/tmux_depend/ncurses,注意两个依赖将分别安装在 tmux_depend 的下一级目录,而 tmux 无需单独的安装目录
  2. 安装两个依赖(以第一个为例)
    1. 进入~/software/tmp/libevent-2.1.11-stable子目录
    2. 执行 configure 命令,指定安装位置
    3. make, make install 走起
1
2
3
4
5
6
7
cd libevent-2.1.11-stable
./configure --prefix=/home/username/software/tmux_depend/libevent --disable-shared
make && make install

cd ncurses-6.2
./configure --prefix=/home/username/software/tmux_depend/ncurses
make && make install
  1. 安装 tmux
    1. 进入~/software/tmp/tmux-3.0a子目录
    2. 执行 configure 命令,指定安装位置等选项
    3. make,这里不需要 install,只要确保可执行文件tmux所在路径可以被找到即可
1
2
3
cd tmux-3.0a
./configure CFLAGS="-I/home/username/software/tmux_depend/libevent/include -I/home/username/software/tmux_depend/ncurses/include/ncurses" LDFLAGS="-L/home/username/software/tmux_depend/libevent/lib -L/home/username/software/tmux_depend/ncurses/lib -L/home/username/software/tmux_depend/libevent/include -L/home/username/software/tmux_depend/ncurses/include/ncurses"
make
  1. 安装完成,接下来把需要的路径添加到 PATH,这里我们在.my_bashrc中实现
1
2
3
# tmux 3.0a
export TMUX_HOME=~/software/tmux
export PATH=$TMUX_HOME:$PATH

最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下

1
2
tmux -V
which tmux

关于tmux的配置可能有很多问题,例如tmux-256color不识别,可行的做法是将ncurses提供的lib/terminfo目录赋值给环境变量$TERMINFO

fish

fish比原本的bash舒服多了,这里选择源码安装一下。

  1. 从官网下载fish的源码包fish-3.3.1.tar.xz,这里并没有采用最新版本,而是采用了ubuntu22所采用的稳定版。
  2. ftp 传到~/software/tmp目录下,解压tar -Jxvf fish-3.3.1.tar.xz,得到~/software/tmp/fish-3.3.1子目录,切换到软件安装目录~/software,建立安装目录~/software/fish
  3. 进入~/software/tmp/fish-3.3.1,fish源码是cmake项目,因此cmake命令直接走起,注意修改一下安装目录即可
1
2
3
4
cmake -S . -B build  -DCMAKE_INSTALL_PREFIX=~/software/fish
cd build
make -j8
make install
  1. 安装完成,接下来把需要的路径添加到 PATH,这里我们在.my_bashrc中实现
1
2
3
# fish 3.3.1
export FISH_HOME=~/software/fish/bin
export PATH=$FISH_HOME:$PATH

最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下

1
2
fish -v
which fish

因为fish本身是基于C++11实现的,我们直接使用系统自带的gcc/g++编译即可,并且不需要修改动态库路径。

ninja

CMake还是搭配ninja比较舒服。

  1. 直接下载njina的源码压缩包
1
curl -LJO https://github.com/ninja-build/ninja/archive/refs/tags/v1.11.1.tar.gz
  1. ftp 传到~/software/tmp目录下,解压tar -zxvf ninja-v1.11.1.tar.gz,得到~/software/tmp/ninja-1.11.1子目录,切换到软件安装目录~/software,建立安装目录~/software/ninja
  2. 进入~/software/tmp/ninja-1.11.1,ninja源码是cmake项目,因此cmake命令直接走起,注意修改一下安装目录即可
1
2
3
4
cmake -S . -B build  -DCMAKE_INSTALL_PREFIX=~/software/ninja
cd build
make -j8
make install
  1. 安装完成,接下来把需要的路径添加到 PATH,这里我们在.my_bashrc中实现
1
2
3
# ninja
export NINJA_HOME=~/software/ninja/bin
export PATH=$NINJA_HOME:$PATH

最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下

1
2
ninja --version
which ninja

ninja实际使用的C++标准很低,可以直接使用系统自带的gcc/g++编译器。如果需要改成高版本的gcc/g++编译器,还需要手动修改CMakeLists.txt,通过添加-wl,rpath=命令来修改动态库的RPATH,否则会找到错误的动态库,运行报错。

Anaconda

使用root用户为服务器的所有用户安装Anaconda,记录一下安装过程。

首先,下载Anaconda的离线安装脚本,大约1个G,下载链接为 https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh。将安装脚本上传到服务器上,使用root用户执行

1
bash Anaconda3-2024.06-1-Linux-x86_64.sh

在安装过程中需要选择安装位置,默认是当前用户的家目录下,将其修改为/opt/anaconda3-2024

base环境中,除了自带的库,还额外安装了CPU版本的pytorch,安装命令如下(联网安装)

1
conda install pytorch torchvision torchaudio cpuonly -c pytorch

至此,root用户安装配置完成。

对于每一个用户(无论是普通用户还是root用户),在使用前还需要进行基础配置:

  • 执行conda initconda会在~/.bashrc的最后添加一段conda所需要的启动命令。由于目前系统还找不到conda,这个命令中必须使用它的完整路径

    1
    /opt/anaconda3-2024/bin/conda init

  • 退出shell并重新登陆,使上述修改生效,此时which conda可以找到正确的路径,一般的conda命令也可以正常使用

  • 为了避免conda在shell中自动激活环境,可以执行下面的操作,此后只有手动执行conda activate才会激活环境

    1
    conda config --set auto_activate_base False

上述配置是针对bash的,针对fish的配置需要使用conda init fish,对应会修改~/.condig/fish/config.fish配置文件。

补充

我其实还需要一个clangd,但是这个搞起来很麻烦:

  • 尝试直接下载的编译好的二进制程序,发现程序依赖的glibc版本要求GLIBC_2.18,比系统上的glibc版本更高,程序无法启动;
  • clangd是LLVM的一个组件,直接拉取整个LLVM项目的源码并编译其中的clangd,过于繁琐(还有更多的依赖和版本问题),很费时;
  • 在本地编译一个比系统版本略高的glibc,提供给clangd使用,参考这篇博客

感觉clangd其实并不是必要的,并且这种问题在版本稍微高一点的系统中就压根不存在,不值得专门去鼓捣这种问题。

PBS本地自动化

下面是我为PBS作业提交加上的一些自动化脚本。

生成项目快照

因为PBS脚本执行时间很长,在执行过程中修改源代码可能会产生影响, 我们必须拷贝整个项目(例如名为demo)到其它位置(例如~/pbshome/)中,在拷贝的快照中提交作业,这样我们对代码的后续修改和现有作业的执行不会产生相互影响。 如果当前项目是一个干净的Git项目,也可以选择直接进行本地仓库的克隆,因为.gitignore的存在,两种行为并不是等价的。

在生成项目快照时,我们可以记录一些关键信息,例如:

  • 设置快照名称,自动加上时间戳作为拷贝后的文件夹名称,放置在~/pbshome/demo/位置下
    • 不提供名称时,文件夹名称形如:snapsho-2024-06-18-11-03
    • 提供名称并且不是git克隆行为时,文件夹名称形如:snapshot-testmail-2024-06-18-11-03
    • 提供名称并且是git克隆行为时,还会加上哈希值,文件夹名称形如:snapshot-testmail-2024-06-18-11-03-bc9716f
  • 在拷贝文件夹中创建专门的日志文件pbs.log:(如果日志文件已经存在,则不会做任何修改)
    • 记录生成快照的拷贝/克隆行为
    • 记录作业的描述,目标

通过create_snapshot脚本实现,最简单的调用命令如下

1
2
create_snapshot
create_snapshot -N name

还可以加上作业的描述和目标

1
create_snapshot -N name --desc desc_string --todo todo_string

create_snapshot脚本放在fenglielie/scripts仓库,便于版本控制。

为了便于可视化操作(查看图片),选择将~/pbshome通过ssh挂载到vlab上(要先创建~/pbshome目录)

1
2
3
sudo apt install sshfs

sshfs ustc:~/pbshome ~/pbshome

取消挂载

1
fusermount -u <path>

生成PBS脚本

我们可以使用脚本自动化生成PBS脚本,只需要通过选项或者交互式地传递一些关键信息即可,这些信息包括:

  • 作业名称(对应自动生成的PBS脚本名为<作业名称>.job
  • 队列名称
  • 使用的节点数(会自动占满每一个节点的所有核)
  • 执行命令

其中:

  • 前几个选项如果不通过命令行传入,会交互式地提示用户填写;
  • 执行命令选项是可选的,如果不在命令行中提供执行命令,会在最后提示用户必须在PBS脚本中手动添加执行命令。

通过create_pbs脚本实现,最简单的调用命令如下

1
create_pbs

可以直接加上可选参数

1
create_pbs -N <jobname> -q <queue_name> -l <nodes_num> -r <command>

例如

1
create_pbs -N testmail -q cu2 -l 1 -r "./a.out"

create_pbs脚本放在fenglielie/scripts仓库,便于版本控制。

PBS自动化邮件通知

PBS作业完成时的自动邮件通知的完整实现方案如下。

本地作业记录和自检

第一部分,在服务器上维护一个简单的作业记录系统:

  • 包括管理脚本~/scripts/pbs_manager和记录文件~/scripts/pbs_records.txt(需要将pbs_manager所在路径添加到PATH
  • 记录文件中的条目包括作业id(纯数字)和作业根目录(绝对路径)
  • 提交作业后,需要手动执行脚本将作业id和作业根目录添加到作业记录文件中,例如pbs_manager add 12223 -d .,这里-d选项指定目录,缺省时默认使用执行命令时的当前目录,在添加记录时会检查作业id的唯一性和目录的合法性
  • 可以手动查询当前的所有记录:pbs_manager list
  • 可以移除特定的记录,提供对应的作业id即可:pbs_manager del 12223
  • 无参数调用pbs_manager会进行自检

自检的逻辑如下:

  • 在shell中调用qstat命令,获取并检查返回的字符串,正常情况下,记录文件中的所有作业id都应该在qstat的返回值中出现,如果没有出现,说明作业已经结束
  • 对于已经结束的作业,我们需要处理记录文件中的对应条目:
    • 在作业根目录下检索以作业id结尾的文件,它们是PBS系统的标准输出和错误输出文件,例如demo.o12223demo.e12223
    • 将检索得到的两个作业输出文件通过scp传递到vlab的固定位置~/pbsdata
    • 通过sshvlab中执行发送通知邮件的任务(具体细节见邮件发送环节)
    • 在记录文件中删除此条目

注意:因为下一个环节的crontab在自动执行脚本时会缺少相关的环境变量,因此这里在脚本中的qstat必须使用完整命令形式。

pbs_manager脚本放在fenglielie/scripts仓库,便于版本控制。

定时任务

第二部分,我们需要使用crontab定时调用pbs_manager进行自检,具体做法如下:

使用crontab -e编辑定时任务,向其中加入两行

1
2
* * * * * /bin/bash -c '~/scripts/pbs_manager 2>&1 | while IFS= read -r line; do echo "$(date +\%Y-\%m-\%d\ \%H:\%M:\%S) $line"; done >> ~/scripts/pbs_manager.log'
5 12 * * 2 /bin/bash -c 'cat /dev/null > ~/scripts/pbs_manager.log'

解释一下,第一个定时任务每分钟执行一次,每次无参数调用pbs_manager,将这个命令的所有输出加上时间戳,以追加方式输出到定时任务的日志文件~/scripts/pbs_manager.log,在绝大部分时间的记录形如

1
2
3
2024-06-18 11:32:01 No records found for checking.
2024-06-18 11:33:01 No records found for checking.
2024-06-18 11:34:01 No records found for checking.

在自检发现任务结束并触发邮件发送行为时的记录形如

1
2
3
4
5
6
2024-06-18 11:19:01 Welcome to Vlab
2024-06-18 11:19:02 Welcome to Vlab
2024-06-18 11:19:02 Welcome to Vlab
2024-06-18 11:19:03 Email sent successfully
2024-06-18 11:19:03 Processed record: 24408
2024-06-18 11:19:03 Record deleted.

第二个定时任务会在每周二中午12:05触发,自动清空日志文件。

发送邮件

因为服务器本身的网络受限,我选择了通过ssh将必要数据传递给vlab服务器,并且在vlab上调用脚本发送邮件的间接方案。

第三部分,在vlab上的邮件生成与发送

  • 发送邮件的脚本为~/scripts/send_mail.py(Python3)
  • 发送邮件涉及的配置文件为~/scripts/config.ini(存储发件邮箱,收件邮箱,授权密码等)

脚本的使用方式例如(这里执行命令所在的位置是用户家目录,即ssh登陆后的默认位置)

1
python3 scripts/send_mail.py --subject "PBS-NOTICE" --body_start "PBS-Job-Finished" --config scripts/config.ini --files file1.txt file2.txt

其中:

  • --subject是必选的邮件标题(不能含有空格,否则解析错误)
  • --body_start是可选的正文开头部分(不能含有空格,否则解析错误)
  • --config是可选的,指定发送邮件使用的配置文件
  • --files是可选的,用于生成邮件正文的文本文件
    • 至多支持三个文件
    • 对每个文件的长度有限制,超过限制的文件中间部分会被省略
    • 文件不存在或者打开失败不影响邮件的发送,会在邮件正文最后保留错误记录

在第一部分中,脚本在自检发现任务结束后,就会通过ssh登陆到vlab并调用上面形式的命令来发送邮件,注意这里的文件也是预先通过scp传递到~/pbsdata的,不能使用原本的路径。

send_mail.py脚本放在fenglielie/scripts仓库,便于版本控制。

USTC LaTeX 使用

USTC LaTeX 是主要支持在线使用的LaTeX平台,基于Overelaf开源版进行的开发,直接支持通过Git仓库同步的功能。 使用Git仓库时,我们可以利用本地的代码编辑器,这比使用浏览器上的编辑器要方便得多,因此记录一下对应的做法。

首先,从网站获取Git仓库链接,通常形如https://latex.ustc.edu.cn/git/xxxxxxx.git,主分支名称为master(这个似乎不可以修改)。 然后将其克隆到本地,并且重新取一个仓库名,例如

1
git clone https://latex.ustc.edu.cn/git/xxxxxxx.git latex_test

由于项目的文件在平台上随时有可能被更改,在本地仓库对代码进行修改之后,远程推送很可能会出现推送失败的情况,对应的处理措施如下:

  • 第一步,我们需要使用其它分支指向本地仓库的最新版本(确保本地的修改不会丢失)
  • 第二步,执行如下命令,确保本地仓库与远程仓库的主分支最新版本保持一致
1
2
3
git fetch --all
git reset --hard origin/master
git pull
  • 第三步,在本地尝试合并分支,然后重新推送

由于平台提供的是HTTPS协议URL,我们在远程操作时需要提供USTC LaTeX平台的用户名和密码, 可以使用下面的命令选择将身份验证信息保存到本地

1
git config credential.helper store

在配置完成后,我们可能需要再执行一次远程操作并输入身份验证信息,Git会将其保存到~/.git-credentials文件中,在下一次远程操作时自动应用。

如果希望改变凭证的存储位置,也可以使用下面的命令将其存储到本地仓库中(显然还需要通过.gitignore将其忽略)

1
git config credential.helper 'store --file=.git-credentials'

注意:

  • 平台的Git仓库不支持force pushforce pull
  • 不建议将多个分支推送到远程仓库,因为平台上无法切换Git分支,只会显示主分支的版本;
  • 平台对于通过Git仓库上传的以.开头的隐藏文件有安全隔离措施(允许通过Git仓库上传,但是在平台上无法查看和使用其内容,只允许下载),在平台上直接创建的隐藏文件是可以查看的,但是一旦通过Git仓库修改,也会被隔离。
  • 有时我们需要改变对这种特殊仓库推送时使用的用户名和邮箱,直接修改仓库内的配置文件即可。
  • 对于Overlaef的git功能操作也是类似的,不过它会直接生成一个token用于登录。

USTC HomePage 使用

直接在Windows的文件浏览器路径栏输入ftp://home.ustc.edu.cn,输入登录名和密码,登录名是邮件帐号@之前的部分,密码与邮件系统一样。

希望对外提供个人主页服务时,必须先创建子目录public_html/, 这个目录里的所有文件均可以通过http://home.ustc.edu.cn/~YourID来访问。在public_html/中存放index.html文件就可以提供默认首页,希望访问其它网页时,在URL中加上相对路径即可。