404E Blog

第 3 页

构建KonaJDK

开发工具

最近准备参加OpenSourceTalent,题目是KonaJDK相关的,首先要构建KonaJDK,这儿我踩了很多坑

尝试在windows构建

  • 我一开始尝试使用mingw构建,但是configure中要求的make版本不一致
    configure: Found GNU make version GNU Make 4.2.1 at /f/App/mingw64/bin/make, but it is not for msys (it says: Built for x86_64-w64-mingw32). Ignoring. configure: error: Cannot find GNU make 3.81 or newer! Please put it in the path, or add e.g. MAKE=/opt/gmake3.81/make as argument to configure.

  • 然后我尝试使用msys2构建,make版本没有问题,但是configure死活不认我装的vs2022,使用vs2013也一样构建失败(后来在ci里看到它使用的是vs2017)
    configure: Could not succesfully extract the envionment variables needed for the VS setup.
    configure: Try setting --with-tools-dir to the VC/bin directory within the VS installation
    configure: or run "bash.exe -l" from a VS command prompt and then run configure from there.
    configure: error: Cannot continue

  • 宣告放弃,下各种版本的vs弄得我头都大了

尝试在Ubuntu构建

  • 首先我电脑里有一个之前用过的Ubuntu22.04,我先尝试在上面构建,但是编译的时候会出现各种语法错误导致无法完成编译

  • 然后我去翻Kona的ci,看到了他的构建脚本,使用的是Ubuntu20.04
  • 最终我下了一个新的Ubuntu20.04镜像,按照ci的构建脚本构建成功了(但是还是要自己apt装一些依赖,这ci依赖不全怎么能构建出来的?

Ubuntu上的构建过程

bash
# ci里装的依赖
apt-get install openjdk-8-jdk gcc-9 g++-9 libxrandr-dev libxtst-dev libcups2-dev libasound2-dev
# 自己安装时缺少的依赖
apt-get install libfontconfig1-dev libfreetype6-dev

bash configure \
--with-conf-name=linux-x64 \
--with-target-bits=64 \
--enable-debug \
--with-build-number=b00 \
--with-boot-jdk=/usr/lib/jvm/java-8-openjdk-amd64 \
--with-zlib=bundled \
--with-freetype-lib=/usr/lib/x86_64-linux-gnu \
--with-freetype-include=/usr/include/freetype2

make images

总结:构建文档没一个能信的,只有ci不会骗人

准备等空了再挑战一下在win构建KonaJDK,成功了再来更新

vscode ssh 插件配置及使用

开发工具

安装ssh插件

刚刚安装好是空白的

配置ssh连接

点击右上角的齿轮

选择一个地方创建设置,此处我选择第一个,他会创建一个新的默认配置

参考 https://zhuanlan.zhihu.com/p/35922004

此处我连接的远程服务器是使用密钥的,示例配置如图

连接远程服务器

配置完成后保存,点击ssh targets中ssh右侧的按钮在新窗口中打开连接

选择服务器类型,此处我是linux

首次连接会提示是否接收服务器指纹,选择continue

若使用的用户不是管理员用户,可能需要参考以下文章配置config和私钥(若使用私钥)文件权限

https://windowsreport.com/bad-owner-or-permissions-on-ssh-config/

远程文件

点击左侧的资源管理器,可以打开远程文件夹(不要打开文件很多的文件夹,比如/,插件会无法监听文件变更)

远程命令行

在下方的状态栏上向上拖动打开命令行

log4j+slf4j Ignoring binding 的解决方案

排障复盘

SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions 1.7.x or earlier.
SLF4J: Ignoring binding found at [jar:file:/F:/AppData/Gradle/caches/modules-2/files-2.1/org.apache.logging.log4j/log4j-slf4j-impl/2.20.0/7ab4f082fd162f60afcaf2b8744a3d959feab3e8/log4j-slf4j-impl-2.20.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See https://www.slf4j.org/codes.html#ignoredBindings for an explanation.

引入依赖org.apache.logging.log4j:log4j-slf4j-impl:$_version_时替换为org.apache.logging.log4j:log4j-slf4j2-impl:$_version_

参考官方文档

使用powershell批量将xlsx转csv

开发工具

最近帮朋友写自动转xlsx到csv的脚本,尝试了aspose-cells和poi,前者闭源还混淆,后者速度慢很多,后来发现powershell脚本可以直接调用excel的api,最后就选择了powershell脚本

注意事项

  1. 此脚本需要电脑上安装Excel
  2. 此脚本需要电脑上安装高版本的powershell

使用方式

  1. 复制脚本到文件并修改文件后缀名到.ps1
  2. 在脚本所在的文件夹中新建文件夹并重命名为input,把需要转换的文件放进去
  3. 右键脚本,选择使用powershell7运行 或者 右键 -> 属性 修改打开方式为pwsh(在安装高版本powershell的位置找),然后直接运行

脚本内容

powershell
chcp 65001 > nul
Echo "将需要转换的文件放在input文件夹中, 输出的文件放在output文件夹中"
if (!(Test-Path input)) { Mkdir input > $null }
if (!(Test-Path output)) { Mkdir output > $null }
$WorkingDir = (Get-Location).Path
$Start = Get-Date -UFormat %s
$Files = Get-ChildItem -Path "input" -Recurse | Where-Object { $_.Name -match ".*\.xls[xm]?" }
$Files | ForEach-Object -Parallel {
    $Start = Get-Date -UFormat %s
    $Excel = New-Object -ComObject Excel.Application
    $WorkingDir = $using:WorkingDir
    $InFileName = $_.name
    $OutFileName = "$InFileName.csv"
    Echo "处理中... $InFileName -> $OutFileName"
    $OutFilePath = "$WorkingDir\output\$OutFileName"
    if (Test-Path $OutFilePath) { Remove-Item -Path $OutFilePath }

    $Excel.Workbooks.Open("$WorkingDir\input\$InFileName").Worksheets.Item(1).SaveAs("$OutFilePath", 62)

    $Time = (Get-Date -UFormat %s) - $Start
    Echo "处理完成 $OutFilePath 耗时${Time}秒"
    $Excel.Quit()
}
Get-Process -name Excel | Where-Object { $_.mainWindowTitle -eq "" } | ForEach-Object { Stop-Process $_.Id }
$Time = (Get-Date -UFormat %s) - $Start
$Count = $Files.Count
Echo "全部文件处理完成, 共${Count}个文件, 耗时${Time}秒"
Timeout -t 3

脚本会从input文件夹中寻找后缀为.xls.xlsx.xlsm的文件,将他的第一张表转换成csv格式并保存到output文件夹

SaveAs的第二个参数可以自行修改,参考

ps powershell还挺好用,比batch强多了

以及一个合并csv的脚本(合并表头)

powershell
chcp 65001 > nul
Write-Output "将合并output文件夹中的csv文件, 输出到output.csv"
if (!(Test-Path input)) { Mkdir input > $null }
$WorkingDir = (Get-Location).Path
$Start = Get-Date -UFormat %s
$Files = Get-ChildItem -Path "output" -Recurse | Where-Object { $_.Name.EndsWith(".csv") }
if ($Files.Count -le 1) {
    Timeout -t 3
    exit
}
# 忽略的行数, 不包括表头
$Ignore = 0
$Flag = $true
$Out = [System.IO.File]::OpenWrite("$WorkingDir\output.csv")
$Writer = New-Object System.IO.StreamWriter($Out, [System.Text.UTF8Encoding]::new($true))
$Files | ForEach-Object {
    $Stream = [System.IO.File]::OpenRead("$WorkingDir\output\$($_.name)")
    $Reader = New-Object System.IO.StreamReader($Stream)
    # 忽略前n行
    if ($Ignore -ne 0) {
        foreach ($__ in 1..$Ignore) { $Reader.ReadLine() > $null }
    }
    $Head = $Reader.ReadLine()
    # 表头行
    if ($Flag) {
        $Flag = $false
        $Writer.WriteLine($Head)
    }

    while ($Line = $Reader.ReadLine()) {
        $Writer.WriteLine($Line)
    }

    $Reader.Close()
    $Stream.Close()
}
Write-Output "全部文件合并完成, 共$($Files.Count)个文件, 耗时$((Get-Date -UFormat %s) - $Start)秒"
Timeout -t 3

win环境下配置gpg密钥

开发工具

本文中使用的密钥为示例密钥,并无实际作用

安装git

https://git-scm.com/downloads

打开git bash

在桌面上右键打开菜单,点击

生成gpg密钥

参考文档 https://docs.github.com/zh/authentication/managing-commit-signature-verification/generating-a-new-gpg-key

输入指令 gpg --full-generate-key

bash
$ gpg --full-generate-key # 输入生成gpg密钥的指令
gpg (GnuPG) 2.2.29-unknown; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want: # 选择你想要的密钥类型,默认即可
   (1) RSA and RSA (default) # 默认值
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? # 回车,使用默认值(rsa)
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096 # 此处我手动输入4096,因为git文档中注明 `密钥必须至少是 4096 位`
Please specify how long the key should be valid. # 选择有效期
         0 = key does not expire # 默认值,永久生效
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) # 回车,使用默认值
Key does not expire at all # 提示密钥不会过期
Is this correct? (y/N) y # 输入y并回车

GnuPG needs to construct a user ID to identify your key. # 需要输入个人信息

Real name: qwert # 输入名字,此处输入的是qwert
Email address: [email protected] # 输入邮箱,此处输入的是[email protected]
Comment: test # 输入注释,此处输入的是test
You selected this USER-ID:
    "qwert (test) <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? # 输入o则确认信息无误,生成密钥;输入q则取消生成并退出

输入o并回车后会跳出弹窗让你输入密码并确认(过短会提示,可以强制使用)

查看已有密钥 gpg --list-secret-keys --keyid-format=long

bash
$ gpg --list-secret-keys --keyid-format=long
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
/c/Users/Administrator/.gnupg/pubring.kbx
-----------------------------------------
sec   rsa4096/25F10366757A2676 2023-02-13 [SC]
      112C798ADD267E3918A0663825F10366757A2676
uid                 [ultimate] qwert (test) <[email protected]>
ssb   rsa4096/9DE000ED74E49E6B 2023-02-13 [E]

导出公钥

在git bash中输入 gpg --armor --export 25F10366757A2676

注意,此处最后的数组是你生成的密钥对应的id,也就是上述步骤中sec开头的行,rsa4096/之后的那一串字符,此处是 25F10366757A2676

导出得到的公钥格式应该是如下格式

bash
$ gpg --armor --export 25F10366757A2676
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGPp2UYBEADkaspaZ4gNTpuPQ66WuWrKmDUvxu8t3A0wXq7HKwcKYyluZZPI
kiujcHgOc9UBSc8eG34LA7mSQFJDoke9bhpnp1OhaIGSikgUluY6sNTy1J7oLK+W
XWrWkQWVIeOOiZri/wB6s5+Ijb9F2f8uAw1SOKj16/cUrsqY8KyWarKlipgYkyGc
uFIEV3S7zMJQsU66QwV122Mq0SU6unRyBMcN3kWMz2aRsak7ijtJWGm52b4gqQwi
KcLzevo2etv04rOzZAd1xSw4KvUoaIuA2wd9t2Yw8yVTy715FG/TrPKJfI/NcoD3
tFGxi24BSbuStJqUUmoCNfLMnIbkZH1RYja6Wwzsr6Jy28jj6veD5ETZsshurUXp
qc27F/SiotOzz1BbbncAkYDyBiaQqKELEZ2h6ovgK1kBODHMgMx0EZVBrrxrp5Jq
f37fdeiTeegoUPiD5crJyM7OT3K+6AZi5OjMQ7tomMRULoUIsqWMUtMrDzCcmbab
geRzrx6xc0LcVQspibU/wHyqvnXa1EnSNA+iL+goZIFr5/0sOvZD+BfjOwjiEKy0
1zXZvErjC7h9nwCpPoetqGjIhgDumJZDaWIASB62f1GeNVd7dpFtVlX8sBz6JlVC
kbyoW8uch2ZHTtraMhkt0YjQr4gUj5l93m5J9n2iWkwZqDZCZrYGviWYcQARAQAB
tBpxd2VydCAodGVzdCkgPDEyM0A0NTYuY29tPokCTgQTAQgAOBYhBBEseYrdJn45
GKBmOCXxA2Z1eiZ2BQJj6dlGAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJ
ECXxA2Z1eiZ2Fy0QANm4kZiWwz28enOCcy6HpOwZSoRT2b0qLgeBDqMpACkeZC+7
iQvSwarNMhm/kgcd80OKVnLtvgIMDBCwDXz+f4Izwm6ffWzgYzUALErPEsii2kb7
pX07tA66dOv+FhiShnxa5+GV7hdjvMZB4MK+ozTPHud/z/CjXVZAK/h1Ig8dliG7
fEhCVKo0MU7OcF9jIp2g8enlJr1wDnFgSLwSidb3TvJl+eRdb1dKy7YwZuI0ZPmH
GeA8TWgo3l7YgFsOkE7FHAVeF2Sz5/RLrnxnltVL5tTBGCaAuk+7BBfE+7EKGCRO
mbeRRGHgmvkjjUw/H1uMWJsQY7vdzmvEE3c3WCZf5ZrsZZpaxVXyNKJPigHsnWXs
7IIbSablCi4qLEyzKDwk9PouAxhy3tSp0WYqwb358fksxHQ7om8fXLzuUbmtx7/+
0UWISigKi8Xno935C5zWxC7Rn9dCjZV2T6IYWyohO2QhyLup2I7QuM8xHGolkPG8
zsYajE4B2VmLaoLWwNI1hAAC/OogOIbG5Kyt+O+TV+i+X1uu9I7ZS+cArJ+drN4z
3GSBVtbGsonQGC5uOEyXppE3rP+8IZJkF6qV7xDU/TEdl2ky+OYaI0QghwNOMmQE
Z9/nojTTSH8nSUWKK7b7JUMF8t0DG1qDzOr5VNfzDsQymonmwV5WNIewqD5uuQIN
BGPp2UYBEAC+kzCBuYnRp1upLCMGo/mlyJhkgAMS2yM7THNu+zuG//wp6684Pvb3
HJTIGo/H0aOq+IJNF4jNxHGDWd2+5gU/RspUqfHPnwiT/PmkbV3Z0/BbkIFu85NE
PCkPOV/yDJnafDknSSI9qi2fz8SW5mPh1hum3gWiWL8yJE2E5SXVN4tcCfkrHXl2
N87yn2EmFZSSEdNVwDX2dvphf6ZTrFeKrhpJUZNQa8srmAmq8GE1rCTqsb2QyIOI
JYW1yeIN12aeaqLo/glCU6VFoOWlsOK2V5ghUr+uS4mmZOfe2XfETwNPTpPkngnX
/jqgFoTKkfaEOd9H/iiQO+OHg5nv+wihFJNmpiNbBCDKMdTaZ4Zzk72EH2eaodzX
KfG9Od0ZSqGw+i6xfHT++SFRNVzlOJM0DMKU/+BhvfmOHsAYGksHAyyQZ3mzUPDn
NEnIG+aaiJHIYpGa1c62k7fi0ch2Ulswi71v2/cGeDV2P1fVjKeDX1xybMruc56Y
kmS14vFn+C4ZwGbldC3ha3iFFnGxegBNQvRh+7P+fkPzqql64v/l4PT0BjUoQ82a
PcZGAaDeoSkWVit87UBi6uKHY2K4SbpKZAcDaYQ5bV8jgfod/DMDNTAvdkB/ud6s
0mLmYO6QOEOFpEpU9FNOUFj5M1FCqXnMM2wGI2KovHERPvAQIchNCQARAQABiQI2
BBgBCAAgFiEEESx5it0mfjkYoGY4JfEDZnV6JnYFAmPp2UYCGwwACgkQJfEDZnV6
Jnb6SQ//Q7lztvTDKhJWg1TPZP/9ImP7Vs98fxcOmUlSv5XNaZCkcL1JQTFfOmpp
aiwUiHd4lwtENat/PoHhAqo8UI1I8KCherRRCXriJ0cpXAkk5TafA5HFRx8zTJcb
OoyE6+m7Sa7MocoVbSlOScUapNP08fO4mRzkNQTXo6zeNryO7lBmeSSfccCqQ5IK
8Ol7omHJ8wJurL4ult+WOke95HiZ+xu1Pqy8FCO6yj6hrA81tEpF1z+4wPoAsnOV
yn4GYPSISO2tmcB3wDxDI0/IyVjpNsqwcNnbh+a7mJLTAWPGzMdBrRD2HsjQAUex
eEEQYbB36F6qQvy6arShIdi7N59GKIgfxRtm2BUa5LWpEus1kn9QJ6Lg1b9G9Fuc
9fK9hNKVVEMQF9Yo07vuPvHrY19wNmkOsUsQdh2nPxdxKmC8KjHaT/xRcxCrRD+J
LhHa1R/0gc/jMNLCayyoqUy1iCVXFLZwljrE9eoFo1+AOLiw5afwQnZxYT1u1Tiy
irJ1kZwtVTQ8eN2IUw7vWPfMaJvhAo3Qj1wXTupc2OHIoDy7bb19fY9LdMfSvKwT
eF9pjYIR1YSiBpHZ1BKXUX6EzxL1c89NCkaLA/CqSb976pWb+DZITutferSLm7xp
ST07kSUapP2OlmRe5icypQUHx9d8hr9OLMPrpXA0apmGPe/3VaY=
=i2+O
-----END PGP PUBLIC KEY BLOCK-----

将公钥导入github

github设置 https://github.com/settings/keys

添加新gpg密钥 https://github.com/settings/gpg/new

文档参考 https://docs.github.com/zh/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account

打开添加新gpg密钥界面并填入title和key

title可以写一个名字,用于区分不同的公钥

key写上面步骤中导出的公钥

按照上述生成的内容填充后应该是如下格式

点击下方的Add GPG key将此gpg密钥添加到git中

设置git在提交中启用gpg签名

开启commit使用gpg签名 git config --global commit.gpgsign true

将 Git 配置为默认对所有提交进行签名 git config --global user.signingkey 25F10366757A2676

设置之后idea若不开启使用gpg签名则会提交失败

设置idea在提交时使用gpg签名

在idea设置中找到版本控制 > git,点击配置GPG密钥,勾选使用GPG密钥签署提交并在下方选择框中选择使用的密钥

之后提交推送时会弹窗提示输入密码

删除gpg密钥

删除密钥有三个选项:--delete-keys--delete-secret-keys--delete-secret-and-public-key
--delete-keys表示从公钥钥匙圈上删除密钥,也就是一同删除公钥和对应的私钥。在分批模式(batch mode)下,密钥必须使用指纹表示,或者使用--yes选项。
--delete-secret-keys表示从私钥钥匙圈上删除密钥。
--delete-secret-and-public-key--delete-keys一样,但是如果私钥存在的话,会先移除私钥。在分批模式下,密钥必须使用指纹表示。

此处在git bash中输入 gpg --delete-secret-and-public-key 25F10366757A2676

注意,此处最后的数组是你生成的密钥对应的id,也就是上述步骤中sec开头的行,rsa4096/之后的那一串字符,此处是 25F10366757A2676

bash
$ gpg --delete-secret-and-public-key 25F10366757A2676
gpg (GnuPG) 2.2.29-unknown; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


sec  rsa4096/25F10366757A2676 2023-02-13 qwert (test) <[email protected]>

Delete this key from the keyring? (y/N) y # 输入y并回车
This is a secret key! - really delete? (y/N) y # 输入y并回车

pub  rsa4096/25F10366757A2676 2023-02-13 qwert (test) <[email protected]>

Delete this key from the keyring? (y/N) y # 输入y并回车
# 弹窗验证

gradle导入authlib依赖

Minecraft
纯文本
repositories {
    maven("https://libraries.minecraft.net")
}

dependencies {
    implementation("com.mojang:authlib:3.11.49")
}

Ubuntu安装Mysql5.7笔记

运维部署

下载

https://downloads.mysql.com/archives/community/

解压

纯文本
tar -xf mysql-5.7.39-linux-glibc2.12-x86_64.tar.gz

创建linux用户和组

纯文本
groupadd mysql && useradd -r -g mysql mysql

设置

注意,以下示例步骤中安装mysql的位置为/usr/local/mysql,mysql数据文件夹为/usr/local/mysql/data

纯文本
vim /etc/my.cnf

参考:http://c.biancheng.net/view/7618.html

这儿的不要乱写,容易导致各种奇奇怪怪的问题

纯文本
[mysqld]
port=3306
user=mysql
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/tmp/mysql.sock
max_connections=200
symbolic-links=0
character-set-server=utf8
default-storage-engine=INNODB
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[mysql]
default-character-set=utf8

[mysqld_safe]
log-error=/usr/local/mysql/error.log
pid-file=/usr/local/mysql/mysqld.pid

文档:https://www.mysqlzh.com/doc/13/78.html

bash
# 创建数据文件夹, 日志文件夹, 设置所有者
cd /usr/local/mysql && mkdir logs && touch error.log && chown mysql:mysql -R *

初始化

纯文本
bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data/ --user=mysql --initialize

解决./mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory

bash
sudo apt install -y libaio-dev numactl

复制 mysql 到系统服务

纯文本
cp support-files/mysql.server /etc/init.d/mysql

解决Unit mysql.service does not exist, proceeding anyway.

修改vim /etc/init.d/mysql

bash
# 若/etc/my.cnf中指定了mysql目录,则此处也需要指定
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data

启动mysql

纯文本
systemctl enable mysql

或者

纯文本
service mysql start

进入mysql命令行

bash
mysql -u root -p
# 在接下来的一行中输入密码

解决./mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory

纯文本
apt-get install -y libncurses*

修改密码

纯文本
-- 更新密码
alter user 'user'@'host' identified by 'password';
-- 刷新权限
flush privileges;

常用操作

以下内容参考于 https://blog.csdn.net/qpzkobe/article/details/102833458

bash
# 创建用户 username替换为用户名, host替换为地址, password替换为密码
# 示例 CREATE USER 'mc'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
# 删除用户 username替换为用户名, host替换为地址
# 示例 DROP USER 'mc'@'localhost';
DROP USER 'username'@'host';
# 授权 privileges替换为权限, databasename替换为库名, tablename替换为表名, username替换为用户名, host替换为地址
# 示例 GRANT all ON playerpoints.* TO 'mc'@'localhost';
GRANT privileges ON databasename.tablename TO 'username'@'host';
# 撤销授权 privileges替换为权限, databasename替换为库名, tablename替换为表名, username替换为用户名, host替换为地址
# 示例 REVOKE all ON playerpoints.* FROM 'mc'@'localhost';
REVOKE privilege ON databasename.tablename FROM 'username'@'host';

# 刷新权限
flush privileges;

screen简单教程

运维部署

Linux screen命令用于多重视窗管理程序。

screen为多重视窗管理程序。此处所谓的视窗,是指一个全屏幕的文字模式画面。通常只有在使用telnet登入主机或是使用老式的终端机时,才有可能用到screen程序。

https://www.runoob.com/linux/linux-comm-screen.html

下文中使用name作为默认的screen名字示例,实际使用中需要替换成你创建的screen的名字

简单的入门使用

创建并进入

纯文本
screen -S name # 创建一个名字为name的screen

挂起当前screen(还可以进入)

在screen中按下ctrl + a,然后按d(注意如果开启中文输入法可能会失效)

查看存在的screen

纯文本
screen -ls # 查看存在的screen

进入挂起的screen

纯文本
screen -x name # 进入名为name的screen(允许多个终端同时进入)

若打开了多个同名的screen, 则需要先使用 screen -ls 列出并找到要打开的screen对应的id, 然后使用 screen -x id 进入对应的screen

纯文本
screen -x 12345 # 进入id为12345的screen

退出当前screen(无法再进入)

纯文本
exit # 若当前处于screen则退出screen, 否则会退出当前bash

特殊用法

后台创建

纯文本
screen -dmS name # 创建一个名为name的screen但是不进入

外部执行指令

纯文本
screen -x -S name -p 0 -X stuff "ls\n" # 外部调用名为name的screen输入ls并回车(\n代表回车)

此处的 -p 0 意为若存在多个screen则选择第0个(从0开始),若你没有同名的screen则可以去掉

外部关闭screen

纯文本
screen -S name -X quit # 从外部关闭名为name的screen

滚动

先按 ctrl + a , 然后按esc

gradle打包依赖进jar

开发工具
kotlin
tasks.create<Jar>("fatJar") {
    archiveBaseName.set(project.name + "-all")
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    manifest {
        attributes["Main-Class"] = "top.e404.bot.loader.Main"
    }
    val exclude = listOf(
        "LICENSE.txt",
        "META-INF/MANIFSET.MF",
        "META-INF/maven/**",
        "META-INF/*.RSA",
        "META-INF/*.SF"
    )
    val dependencies = configurations.runtimeClasspath.get().map(::zipTree)
    from(dependencies).exclude {
        it.path in exclude
    }
    with(tasks.jar.get())
}

或者使用 shadow 插件

kotlin
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
  kotlin("jvm") version "1.7.21"
  id("com.github.johnrengelman.shadow") version "7.1.2"
}

group = "top.e404"
version = "1.0.0"

repositories {}

dependencies {}

tasks.shadowJar {
  archiveFileName.set("${project.name}-${project.version}-all.jar")
}