写在开始最近给自己的搜索机器人加了一个OCR识别的功能，本来想尝试着直接识别来着，不过发现效果并不是很好，接下来继续用可能得考虑下有啥方式能提高文本的识别率了。其中有个踩坑就是Nuget上的Tesseract构建的动态链接库只有Windows版，没有构建Linux版的动态链接库，所以直接在Linux上使用就会报错，然后会缺少那几个动态链接库。一个是libleptonica-1.80.0.so另一个是libtesseract41.so，除此之外如果用到了System.Drawing的话还需要libgdiplus库。接下来的解决方案只针对Debian 10，如果是非glibc环境的话自己参考下解决吧，用了好一阵子的alpine之后发现，在上面折腾的时间已经远大于节约的体积了，所以在Docker里面还是用Debian比较方便。构建leptonica构建之前先准备好编译环境apt update -y && \ apt upgrade -y && \ apt install automake ca-certificates g++ git libtool make pkg-config asciidoc docbook-xsl xsltproc libpango1.0-dev git cmake -y然后准备一下LD_LIBRARY_PATH，这个是为了给Tesseract用的，所以现在不写也可以。export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib接下来准备一个存放最终输出文件的目录mkdir -p /app/out/x64然后在/app目录下克隆leptonica并进入git clone https://github.com/DanBloomberg/leptonica cd leptonica切换到1.80.0版本的commit上去git checkout 1ac72c93fef1a5eb76b76d6723d2aee843dd6e51然后使用autogen.sh、./configure、make -j4、make install四连./autogen.sh ./configure make -j4 make install这里不能用cmake方案，用cmake的话输出文件里面找不到动态链接库，至于原因我没去找，毕竟做成自动编译脚本的话还要改里面的东西就有点麻烦了。执行完成之后就会把liblept.so安装到/usr/local/lib里了，然后直接复制到我定义的输出目录里cp /usr/local/lib/liblept.so.5.0.4 /app/out/x64/libleptonica-1.80.0.so这样子libleptonica就算是构建完成了。构建Tesseract这个构建思路也是类似的，老样子在/app目录下克隆tesseract并进入git clone https://github.com/tesseract-ocr/tesseract.git cd tesseract然后找到4.1.1版本的commit，切换过去git checkout 75103040c94ffd7fe5e4e3dfce0a7e67a8420849然后使用autogen.sh来生成项目./autogen.sh接下来创建输出目录，然后使用cmake编译就可以了mkdir build cd build cmake .. make -j4然后拷贝动态链接库到定义的输出目录cp libtesseract.so.4.1.1 /app/out/x64/libtesseract41.so这两个文件的x64版本的动态链接库就构建完成了。配置运行环境的依赖我使用的时候还遇到了个找不到libdl的问题，这个应该就是缺少了libgdiplus的问题，用下面的命令安装就行了。bash完整的构建命令这个可以抄一下我的Dockerfile，下面贴上我Dockerfile的配置FROM moderras/dotnetsdk:5.0 AS build-env WORKDIR /app RUN export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib && \ apt update -y && \ apt upgrade -y && \ apt install automake ca-certificates g++ git libtool make pkg-config asciidoc docbook-xsl xsltproc libpango1.0-dev git cmake -y && \ mkdir -p /app/out/x64 && \ git clone https://github.com/DanBloomberg/leptonica && \ cd leptonica && \ git checkout 1ac72c93fef1a5eb76b76d6723d2aee843dd6e51 && \ ./autogen.sh && \ ./configure && \ make -j4 && \ make install && \ cp /usr/local/lib/liblept.so.5.0.4 /app/out/x64/libleptonica-1.80.0.so && \ cd /app && \ git clone https://github.com/tesseract-ocr/tesseract.git && \ cd tesseract && \ git checkout 75103040c94ffd7fe5e4e3dfce0a7e67a8420849 && \ ./autogen.sh && \ mkdir build && \ cd build && \ cmake .. && \ make -j4 && \ cp libtesseract.so.4.1.1 /app/out/x64/libtesseract41.so 大概就是这样吧写在最后虽然最后也没用上啥吧，这个OCR功能暂时被我废弃掉了，因为识别质量太差。所以写个博客留念一下折腾的这个东西吧，不得不说 .NET 的东西和Linux总是相性不和呢，每次把在Windows上跑得好好的东西移植到Linux上跑总是会出点问题，还经常是因为Nuget包里面缺少了指定平台的动态链接库或者依赖这种问题，真令人头大。
写在开始最近从PT站下的视频直接导入到Jellyfin中集数识别不好，但是又不能直接改名，于是发现了一个好办法，那就是创建硬链接，将新建的硬链接修改成合适的名称之后放在合适的文件夹就可以不重复存储，又能保证两边的软件都正常识别，但是只能对文件设置硬链接，所以想办法让它能够批量创建。解决方法在cp命令中有一个参数是-l这个参数是以硬链接的形式复制文件，配合-R就可以将整个文件夹中的文件以硬链接的形式复制到新的地方，整体命令示例如下：cp -l -R SourcePath TargetPath大概就是这个样子了，这样就可以将整个文件夹中的所有文件都创建一个硬链接到新的文件夹了。写在最后其实就是一个命令的很简单的使用方法，不过回了之后还是能方便很多的，也不用花大力气写个复杂的程序自动匹配了，也挺方便的。
写在开始这里写一些Linux上常用的清理空间的操作运行环境：bashDocker清理所有名字为的容器docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker stop docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker rm docker images|grep none|awk '{print $3 }'|xargs docker rmi清理所有未启动的容器docker images|awk '{print $3 }'|xargs docker rmiSystemd清理一天前的日志journalctl --vacuum-time=1d清理日志到剩余1Mjournalctl --vacuum-size=1M写在最后服务器的话基本上常见的清理就是清理日志和清理无用的软件， 因为我都是用docker的， 所以也就是清理掉版本更新之后剩下的的无用镜像了。
写在开始使用Hyper-V的时候他会自动分配一个Default Switch这么一个网卡用于NAT， 然而这个网卡的ip似乎每次重启都会自动更换， 所以这个就挺令人烦恼了， 毕竟如果Hyper-V虚拟机里面是一堆linux的话那每次都是自动更换ip的， 连接起来还是很麻烦的。 所以我打算在内网给解决掉这个问题， 把IP地址至少可以接近静态的， 之前那个连IP段都要变确实有点受不了。技术选型其实这个可以直接在虚拟机里跑一个OpenWRT之类的东西的， 但是鉴于我有一个这样子的虚拟机， 而且还被我莫名其妙搞坏了， 这次我就手动搭建一个路由器系统了。 至于选哪个系统， Linux用的比FreeBSD之类的熟悉一点， Windows太占资源。 然后基于节约资源的角度考虑， 我用了 Alpine Linux。 毕竟这个系统的体积小。 而且这个系统我在玩Docker镜像的时候经常用， 所以也不算陌生。其他的东西也就是用vagrant来操作hyper-v了， 这样子会简单点。那开始吧下载 Alpine Linux 的 Box先去找找有没有现成的Vagrant的Box， 然后我发现了这个Box， 这个Alpine Linux的Box支持Hyper-V的版本。 所以就用这个了。那首先随便找个目录， 然后输入vagrant init generic/alpine310 sudo vagrant up --provider=hyperv因为不是用管理员打开的这个终端， 然后如果操作Hyper-V的虚拟机的话需要管理员权限， 所以需要提权。 这里推荐一下这个人的sudo脚本。 感觉还是挺好用的。顺便一提， vagrant是用curl来下载box的。Hyper-V部分的设置在vagrant下载box的这一会去设置一下Hyper-V那边的东西。打开Hyper-V管理器， 在右侧找到虚拟交换机管理器点开之后创建一个内部的交换机名称随意， 注意是要设置成内部网络， 就像这样然后点确定就好。Vagrant Box 下载完成后vagrant up执行过程中会打印出类似以下的输出这个时候选择 Default Switch就好然后接下来会出来一堆输出， 其实也不用在意是啥。然后sudo vagrant halt关闭这个虚拟机， 接下来往里面添加一个给内网用户使用的网卡。首先要在Hyper-V控制台里面找到这个虚拟机， 然后点击它， 右边会出来一排按钮选择设置。 然后选择添加硬件里面有一个网络适配器， 点击之后选择添加。然后选择之前创建的那个内部网络。选择完成之后大概长这个样子然后点击确定， 回到这里点击启动重启开机。接下来就sudo vagrant ssh进入这个虚拟机里操作就好。构建一个简易的软路由器的基本思路首先要有一个DHCP服务器给内网设备分配IP用， 然后要有一个DNS服务器给内网设备提供DNS服务， 最重要的还要有一个NAT和转发来让内网设备可以通过NAT来连接到外部网络， 然后还需要能够回来。 这样子一个路由器就完成了。那么我们一步一步做就好软路由构成的基本选型使用Dnsmasq来给内网设备提供DHCP和DNS， 然后用iptables创建一个NAT和处理请求转发。曾经还考虑过使用AdGuardHome来提供DHCP和DNS服务来着， 奈何它的DHCP看起来不工作的样子， 也很不稳定的样子， 所以我就抛弃了这个选择。那么就进入软路由里进行操作吧毕竟是个国外的Box， 所以自带的软件源自然不会很快， 这里换成中科大的源。首先看一下这个源是啥cat /etc/apk/repositories然后他输出了https://dl-4.alpinelinux.org/alpine/v3.10/main https://dl-4.alpinelinux.org/alpine/v3.10/community中科大官方提供的一键脚本是这样的sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories这样子很明显不能成功替换， 所以要修改成这样子sudo sed -i 's/dl-4.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories替换完成之后执行sudo apk update更新完成之后就可以准备安装软件了。需要安装的软件因为这个Box非常精简， 精简到连iptables都没有， 所以要装这些东西：dnsmasqiptablesip6tables那么就一条命令加上去吧sudo apk add dnsmasq iptables ip6tablesDnsmasq 配置接下来配置一下Dnsmasq。 在这之前先确认一下自己的网卡ip addr然后输出了三个网卡， 一个是lo， 一个是eth0， 一个是eth1。eth0是走了Default Swtich的， 算是路由器的WAN口， eth1是走了内部网络的， 算是路由器的LAN口， 确定了这个之后开始配置Dnsmasq。sudo vim /etc/dnsmasq.conf接下来我就贴一下我改了的配置， 然后一条一条说好了。resolv-file=/etc/resolv.conf interface=eth1 dhcp-range=192.168.1.50,192.168.1.150,255.255.255.0,12h dhcp-option=option:router,192.168.1.1 cache-size=500 conf-dir=/etc/dnsmasq.d/,*.conf这些是整个dnsmasq.conf里面使用的参数。resolv-file 是声明了上游DNS服务器的地方， 这个我直接用了系统自动配置的DNS， 反正能上网， 所以问题不大。interface 是声明DHCP服务器启动的接口， 这里要设置LAN口的， 所以是eth1dhcp-range 这个就挺好懂了， 就是设置DHCP自动分配的一些设置， 第一个是起始IP， 第二个是结束IP， 第三个是子网掩码， 第四个是DHCP过期时间。dhcp-option这个是提供了一些别的参数， 这个是为了给下游设备提供网关的一个设置， 最后面是设置网关IP的， 我设置为192.168.1.1， 过会我会把路由器的 LAN IP 设置为这个的。cache-size 这个好像是DHCP缓存， 会让你缓存之前DHCP分配的历史记录， 下一次这个设备重新获取IP的时候会先走缓存找到上次的IP。 这个后面的数字随缘设置就好， 算是个可以优化的点吧。 我就随便设置了个500， 不改也可以。conf-dir 这个默认就带着的， 会读取这个目录下面的conf文件， 来自定义配置Dnsmasq， 我也没改， 就放上去了。配置完之后保存就好， 接下来设置LAN口的静态IP。配置 LAN 口的静态 IP那就直接进interface文件里加上这个接口的静态IP就好了sudo vim /etc/network/interfaces打开之后你会看到这样的东西auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp hostname alpine310.localdomain然后在后面添加上auto eth1 iface eth1 inet static address 192.168.1.1 network 192.168.1.0 netmask 255.255.255.0 broadcast 192.168.1.255这算是一个很经典的配置方式了吧。address 设置这个接口的静态IPnetwork 这玩意其实我也不知道是啥， 但是应当是设置为这个网络的起始IP的前一个， 也就是常见的监听整个网络的那个IP。netmask 这个是子网掩码broadcast 这个是广播地址这些配置完之后重启一下network服务sudo service network restart然后你就可以启动Dnsmasq了sudo service dnsmasq start接下来配置 iptables因为只配置IPv4， 所以我就没有管IPv6的转发，直接执行下面四条命令就可以了sudo iptables -A FORWARD -i eth1 -s 192.168.1.0/255.255.255.0 -j ACCEPT sudo iptables -A FORWARD -i eth0 -d 192.168.1.0/255.255.255.0 -j ACCEPT sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE sudo /etc/init.d/iptables save第一条是允许从eth1进来的来源于那个子网的连接第二条是允许从eth0的数据到那个子网里就是一条允许出一条允许进第三条就是把这个挂到POSTROUTING链上第四条是保存这个iptables记录。这个东西多少还是有点晕。 其实我自己也说不太清楚。所以引用一句这位老哥的话第三条表示把数据最终的POSTROUTING定向到eth0也就是WAN口上，使用MASQUERADE转译是为了保证NAT出去的地址是固定的。（其实好多细节也是从这里看到的， 还有这里）然后启动开内核的IP转发， 这个版本的 Alpine Linux 有一个/etc/sysctl.d文件夹， 里面有一个00-alpine.conf的文件， 所以你可以仿照着这种文件格式添加一个01-router.conf之类的文件添加上这些东西， 或者也可以直接添加到00-alpine.conf里面， 看你的个人爱好了。然后在那个配置文件里添加上这么一条net.ipv4.ip_forward=1似乎这时候sysctl -p并不生效， 所以还是要重启一下比较好。给这两个东西加一个开机自启Alpine Linux 的服务管理器是OpenRC， 一个比较轻量而且经典的进程管理器。rc-update add dnsmasq rc-update add iptables给自己的宿主机设置一个静态IP这个就随缘设置一个就好， 右键托盘里的网络打开"网络和 Internet"设置找到里面的更改适配器选项。然后找到内部网路右键属性双击 Internet 协议版本 4简单配置一下就好了， 这个时候不建议设置网关和DNS， 设置了DNS的话可能会导致系统DNS走了这个， 导致出现循环。 网关也是。其实到这里就结束了， 但是我还需要另一个东西接下来装一下vlmcsd， 懂得都懂， 不知道的就不用管了。直接抄一下人家的Dockerfile其实就好， 直接在终端输入sudo su apk update \ && apk upgrade \ && apk add --no-cache build-base gcc abuild binutils cmake git \ && cd / \ && git clone https://github.com/Wind4/vlmcsd.git vlmgit \ && cd vlmgit \ && make \ && chmod +x bin/vlmcsd \ && mv bin/vlmcsd / \ && cd / \ && apk del build-base gcc abuild binutils cmake git \ && rm -rf /vlmgit \ && rm -rf /var/cache/apk/*等着结束之后会在根目录下出现一个vlmcsd， 然后mv /vlmcsd /usr/local/bin/放到一个比较正常的目录下。 配置一下service。 于是就进入/etc/init.d里面创建一个文件， 内容大概这样子就好。#!/sbin/openrc-run description="vlmcsd Server" pidfile="/run/$RC_SVCNAME.pid" command="/usr/local/bin/vlmcsd" command_args=" -D -d -t 3 -e -v" command_background=true extra_commands="checkconfig" depend() { need net after firewall } stop() { if [ "${RC_CMD}" = "restart" ] ; then checkconfig || return 1 fi ebegin "Stopping $RC_SVCNAME" start-stop-daemon --stop --exec "$command" \ --pidfile "$pidfile" --quiet eend $? }创建完成之后给他加个可执行权限chmod +x vlmcsd然后启动service vlmcsd start添加开机自启rc-update add vlmcsd就完工了。写在最后之前一直以为人工做一个软路由很麻烦来着， 结果这么操作了一下发现还是很简单的， 至少现在思路明确了， 整体来说就简单好多了。
写在开始我的Arch Linux上面安装的rime-ibus默认输入是繁体中文，但是我日常要用简体中文，然后每次切换输入法的时候都要按一次F4我感觉很麻烦，所以就找了一下怎么修改简体字。修改默认的那个的配置文件我的这个配置文件在这里~/.config/ibus/rime/build/，所以看一下这个目录下面的文件:bopomofo.prism.bin bopomofo_tw.prism.bin cangjie5.prism.bin default.yaml luna_pinyin_fluency.schema.yaml luna_pinyin.schema.yaml luna_pinyin_simp.schema.yaml luna_quanpin.schema.yaml stroke.schema.yaml terra_pinyin.schema.yaml bopomofo.schema.yaml bopomofo_tw.schema.yaml cangjie5.schema.yaml luna_pinyin_fluency.prism.bin luna_pinyin.prism.bin luna_pinyin_simp.prism.bin luna_quanpin.prism.bin stroke.prism.bin terra_pinyin.prism.bin然后我用的是明月拼音所以我第一反应看到的是luna_pinyin.schema.yaml ，似乎也猜对了。拉到底找到这里：switches: - name: ascii_mode reset: 0 states: ["中文", "西文"] - name: full_shape states: ["半角", "全角"] - name: simplification states: ["漢字", "汉字"] - name: ascii_punct states: ["。，", "．，"]然后改成这样：switches: - name: ascii_mode reset: 0 states: ["中文", "西文"] - name: full_shape states: ["半角", "全角"] - name: simplification reset: 1 states: ["漢字", "汉字"] - name: ascii_punct states: ["。，", "．，"]其实就是加一个reset的选择选成简体中文，就这样就结束了。写在最后这个就是这样子了，还算容易，但是不是很好找，因为网上一般都是用F4或者ctrl+\`实现的， 这种就要每次打开都要设置一遍，比较麻烦，所以这样子会比较省事一点若干年后的补充其实正确用法应当是在luna_pinyin.schema.custom.yaml（经评论指正这里应该是luna_pinyin.custom.yaml)文件里编辑这一段， 这样就可以保证更新rime的时候不会被覆盖掉原来的配置了。所以在luna_pinyin.custom.yaml中应当写的内容为# encoding: utf-8 patch: switches: - name: ascii_mode reset: 0 states: ["中文", "西文"] - name: full_shape states: ["半角", "全角"] - name: simplification reset: 1 states: ["漢字", "汉字"] - name: ascii_punct states: ["。，", "．，"]
写在开始其实就是想找一个简单的base64的编解码工具，然后就发现了linux上就有这个命令，所以我就直接用了。命令介绍默认状态（编码）命令： base64效果： 从标准输入读入然后ctrl+d之后结束，将输入数据编码，所以可以用管道解码参数： -d用法： base64 -d效果：同上，只不过就是这个是解码base64用的从文件中读入（编码）命令： base64 filepath/filename效果： 从这个文件读入数据然后编码成为base64之后从标准输出输出，所以也可以用管道或者重定向从文件中读入（解码）命令： base64 -d filepath/filename效果：同上，只不过是解码忽略非字母表字符参数： -i效果：就是忽略掉某些特殊字符，一般解码的时候加上就好。
写在开始昨天有给某人写了一个C语言的作业，内容是写两个线程，然后在一个线程里打印出另一个线程的线程号。第一个线程结束后再结束第二个线程，内容就是这样子。代码内容其实这个写法就是用了一下pthreads里面的几个函数就可以实现了。我第二个线程打印第一个线程的线程号的方式是在第一个线程结束之后的返回值里面添加上第一个线程的线程号，然后第二个线程join一下第一个线程，这样等待着第一个线程结束之后就可以获取到第一个线程当时获取的线程号了，整体思路就这样子。接下来是代码#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <sys/syscall.h> #define gettid() syscall(__NR_gettid) void * tr1(){ printf("this is thread 1\n"); pthread_exit((void *)gettid()); } void * tr2(void * thread1){ void * thread_id; printf("this is thread 2\n"); pthread_join((pthread_t)thread1,&thread_id); printf("%d",(int*)thread_id); pthread_exit(NULL); } int main() { pthread_t thread1,thread2; pthread_create(&thread1,NULL,tr1,NULL); pthread_create(&thread2,NULL,tr2,(void *)thread1); pthread_exit(NULL); }写在最后方式也是挺简单的，但是至少达到目的了，所以这样就可以了。
Try To Install An Arch Linux On The Virtual Machine
Before long I just in my senior high school. I try to install a arch Linux. Because I see a blog or a answer and find that if you want to study Linux try to use arch Linux or gentoo Linux. And it can be build as whatever you want. So at that time, I download an arch Linux and try to install it on the virtual machine named VMware. After I mount the ISO on the virtual machine, I found it just have a terminal. So I searched tutorials on the internet. Because at that time I can't over the wall, I can only use Baidu. So I searched tutorials for a long time. But I didn't find any useful tutorial. I just followed an old tutorial. So in the end, I failed to install that operating system. But now I think I can try it again because I have Google and arch Linux's wiki also some tutorials which seemed newer. So I think this time I may be succeed.So this time I will say how to install a arch Linux on the VMware. Firstly, create a new virtual machine. I think it's easy. So I didn't say that. I just say I give virtual machine 1Gib memory and 20G hard disk. This time I just use legacy boot, because I try uefi boot and it may not work at virtual machine. Then I start the virtual machine. And it will show :Select the first one. And then you can see:My hard disk is in /dev/sda.So it need to use cfdisk /dev/sda to partition my virtual disk.Select dos.I give / 19G and give swap 1G.Then select write and then quit.After quit, it need to mkfs. Using mkfs.ext4 /dev/sda1to make file system as ext4. Also the swap is need to be formatted. Using mkswap /dev/sda2 and then swapon /dev/sda2 to use swap.Then mount /dev/sda1 /mnt to mount the new disk parted. And then vim /etc/pacman.d/mirrorlist to change a faster software source.Server = http://mirrors.163.com/archlinux/$repo/os/$arch Server = http://mirrors.cqu.edu.cn/archlinux/$repo/os/$archAdd this on the top is OK.Then flush the pacman pacman -Syy.And start to install the system.pacstrap -i /mnt base base-develJust press enter is OK. Then it will install.Then use genfstab -U -p /mnt > /mnt/etc/fstab to create fstab file (just a safety belt).Then you can check that file in order to be safely.Then join new system arch-chroot /mnt /bin/bash . Be safety and command mkinitcpio -p linux . Then passwd. After you press enter write your password. Then set host name echo yourhostname > /etc/hostname. Then add it to /etc/hosts as:127.0.0.1 localhost.localdomain localhost yourhostname ::1 localhost.localdomain localhost yourhostnameThen download grub and installpacman -S grub os-prober efibootmgr grub-install --recheck /dev/sdaIf using uefi :grub-install --recheck /dev/sda --efi-directory=/bootThenrunninggrub-mkconfig -o /boot/grub/grub.cfgAt one time I didn't run this, grub's boot UUID is not true.Then make dhcp run when system run systemctl enable dhcpcd.service.After I run it I get an error Piix4_SMBus: 000:00:07.3: Host SMBus controller bus not enabled. I searched on the Google and find a question in ask Ubuntu the same as mine. Just adding a black list in the system is OK. It's in the /etc/modprobe.d/blacklist.conf. Just adding blacklist i2c-piix4 and saving then restart is OK.The last error I get is failed to start login service. And I didn't find any useful answer. Also it is not appear when I restart and restart and restart.ðŸ˜¥ðŸ˜¥ðŸ˜¥Now it runs!