Linux | Unix生存简易指南

2020 12 13, Sun

最近老能遇到Linux啊macOS啊Python啊Go啊什么的新人,问各种奇奇怪怪的问题。简单说一下怎么可以让自己的路更好走一些。

不讨论推广的问题,也不讨论谁更好的问题。我认为需求决定选择,需求决定市场。

先说一点虚的

我觉得有些前提在一开始说清楚对谁都好

观念改变

很多人用Linux上来就问,有没有VC++6。这和去麦当劳问有没有肯德基的金汤肥牛饭有什么区别?

换一个环境换一个生态换一套习惯,几乎是必然的事情。即使我们常用的软件常用的功能在另一个生态中出现了,也可能会有非常多的功能不同的地方。比如说你知道macOS在卷内拷贝不会多占用空间吗?

在一个新生态里活下去的更好的办法是适应新的生态,找到适合自己的、使用新生态完成各种任务的方式。

英语

英语的确是很多人的一道槛,很多人也不大愿意读我的态度比较简单:活在一个小世界里面没啥问题,但是如果有人在小世界里面拼命劝别人外面的世界不会比小世界丰富多少,那请这个人安静一点,以免以后遇到别人显得自己无知。

no offense. 只是我比较气有的人讽刺别人努力。

问问题

经常可以看到有人这样问问题:

  • A:有大神吗?
  • B:怎么啦
  • A:(贴了一段配置或者代码)
  • B:啥问题
  • A:我上面贴了啊

这里面就有两个问题

  • 第一个是何必要有人愿意回答了才抛出问题,完全可以直接抛出问题,愿意回答的看到问题就会解答,如果彻底没人回答,你就把问题一个个发到各个群里面,学技术的大家看到指教的机会都会手痒痒想炫耀一下的。
  • 另一个问题是你的问题是什么,应该描述清楚。贴一个配置文件不是描述问题,贴一段代码不是描述问题,贴一张截图但是没有说明也不是描述问题。

问问题的人应该把希望达成什么目标、自己做了什么、这一步期待的结果是什么、哪里和期待不一样、有没有验证过前一步是不是正确的罗列出来,如果有自己尝试了什么或者是最小的可复现问题的例子,那当然是更好地。

一次性把问题描述清楚发到各个群里面、等所有的群的大佬一起给出来结论不好吗?

为自己的决定和操作负责

以前用Windows,Windows作为一个商业的通用的操作系统承担了一个不那么称职的Babysitter的角色,但是在大部分的Unix下,你需要为自己的行为负责,会给用户极大的权限。我见过的不这么搞得也就是macOS、Android和iOS。

这就要求我们对自己负责,我们需要尽可能搞清楚自己有什么问题,理解自己的问题,找到合适的解决方案,备份需要保留的东西,最后应用我们的解决方案。

这也是为什么大神可以变成大神的原因。不是用了Unix就会变得很牛逼,也不是Unix本身牛逼,而是我们在赋予权力后,一点点踩坑形成这么一种思考的习惯,这样的习惯让人一点点变强。

桌面不好使?X没什么生态?没有能用的软件?

听到不少意见说Linux桌面没软件。

如果是说桌面环境本身,Linux有三类桌面环境,一类是出厂即用的,比如说Gnome3、Gnome2/Gtk(以及分支Budgie、Mate、Cinnamon)、KDE/Plasma,一类是简单可用也有比较高的配置灵活度,比如说xfce、lxqt这类,再就是对新手来说比较反人类的自行配置的一类了,比如说i3wm。

至于软件生态,我觉得大致有两种可能性,一种是有些类别或者厂商的软件,是真的没有或者做的稀烂,举个例子QQ,一种是很多人不了解生态,所以不知道有一些非常好使的工具。

稍微列举一些我知道的可以帮助你找到你需要的软件的地方:

Arch Wiki - List of Applications

列举了常用的很多软件,从办公到娱乐一应俱全。

Wiki其他的页面也有很多cookbook性质的指导。

Gentoo Wiki

婴儿看护级别的指导。

Alternative to[https://alternativeto.net]

翻译成中文就是"…的替代品",很多软件都有替代的,这个网站还有评论啊什么的。

StackShare[https://stackshare.io]

也是软件的替代和评论,主要是比较两个软件的形式,推荐程度更倾向于企业的使用量,换句话说就是有谁趟过浑水踩过坑。

下载慢,开发用的软件包旧

目前全球范围内,除了Deepin及其衍生品以外,应该没有很多国产发行版在国内有源,所以会慢很多。而且因为发行版需要稳定的环境,所以发版过程中会有冻结版本的步骤。也就是说一个版本的发行版,大部分的软件包版本是不会升大版本甚至小版本的。滚动升级的Linux有另一个极端的问题,软件包经常会太新,开发可能会需要追着工具版本,这个时候我们需要能自己控制这些问题。

我们分具体问题解决

下载慢

代理

这个不提了,敏感。但是只要不是反动的东西一般没事儿。顺带一提,我们国家可能还没有特别好,那我们为啥不监督它同时做一些贡献让它更好呢?

换源

很多包管理工具,包都是从固定的地方下载,这类站点一般叫repository。但是全球用户都从一个地方下载会给服务器造成很多压力,而且地理位置限制有可能会比较慢,用cdn又需要钱,开源项目没有那么钱,怎么办呢?

让有需要的团体建立公开的镜像服务mirror server,也就是把原来的目录结构照搬过来,通过http开放给大众使用。公司或者企业或者组织得到了宣传,包管理的服务器压力也得到了缓解,并且对大众来说可以更快的从更近的地方下载到软件包。对于有的学校流量计费的学生来说,校内软件源是非常重要的省流量的途径,而且避免了一波更新没下完、下一波更新悄然而至的尴尬局面。

国内很出名的源包括并且不限于清华源/清华咸鱼站中科大源163源等等,大部分的站同时提供Linux发行版包管理源的镜像、使用方法和一些常用文件的下载页面。跟着帮助一步步配置就好。

使用时注意选择自己的版本号和架构,尤其是现在ARM开始大规模投入使用以后。经常可以看到小伙伴使用不合适的版本或者架构把自己版本搞崩的。

Ubuntu的软件更新器可以自动选择源,在软件更新器的设置里面,找到软件源的部分,选择更多,弹出的窗口可以自动选择源,不过不一定选得到最适合自己的,可以直接选择一个源。

除了系统包管理的源以外,也有些开发工具或者运维工具有自己的源,比如说语言里面很典型的Python/pypi、Python/anaconda、Node/npm、Dart/pub,运维工具里面很典型的Chef、Docker。

  • 不少镜像站带着Pypi一类的镜像
  • 有一些源是专门搞特殊的工具的,比如说淘宝的npm源,或者各家的私有Docker加速器。
  • 有些工具本身支持自己协议的代理的,比如说Go有GOPROXY可以解决不少问题(https://goproxy.io、https://goproxy.cn)

软件包老旧

发行版自带软件太旧,刚才提到还有个类似的问题是太新,问题的本质都是我们需要对自己需要用的软件做一些控制,主要是版本上的控制,这个需求本身其实还好,不会是啥大问题。但是Unix上面设计既可以说优秀也可以说瓜皮的地方,就是系统内所有东西共用同一个软件包,比如说我更新了一个版本,有个需求依赖Qt5.6了,一般打包的时候会直接用系统内的库打包,就会导致我的程序Backport到老一点点的系统上时,出现官方源因为系统里面没有这个版本或者更新的Qt无法打包,但是又不好给你开小灶,导致局面一度陷入了尴尬的情况。但是也不是不可以解决。

官方源本身带多个版本

很多系统会在官方源带多个版本的软件包,比如说clang7/8/9啊什么的,brew有很多包是xxx@version也是为了解决多个版本共存而生。这是最简单的情况了。

系统本身可以增加源

很多版本系统都可以支持多个不同类型的源,Ubuntu支持PPA,红帽可以加repo,Arch则是可以用不同的mirror中的不同repo。

我这几年不怎么用Ubuntu,不大清楚PPA的情况。简单搜了一下,UbuntuUpdates.org罗列了很多软件包。选择自己需要的下载安装就行。

macOS的homebrew有cask和tap,tap是第三方维护的二进制包,cask主要是安装脚本并没有打包好的二进制,暂且不说这俩。

红帽子的repo有自己的SIG、有copr、也有很多第三方源。SIG是一些维护的比较好的一些软件,copr性质和homebrew的tap差不多、是用户自己维护的二进制包,第三方源有nginx这种自己的源、也有elrepo这种其他人维护的内核的源或者rpmfusion维护的软件源。这些源我自己体验的话质量都尚可。

语言SDK支持项目内使用不同版本

很多语言的SDK支持项目用不同版本,有些语言有不同的SDK,有些工具链会支持一些有意思的特性。

自己本身支持有不同的环境、使用不同的包的,我自己常用的就是Golang(vgo)、NodeJS、Python3(venv)。只有NodeJS毒了一点。

有不少语言有工具链支持不同的环境使用不同的包的,比如说C++有CMake和更进一步的Conan,Java有基于maven仓库的mvn和gradle。

其他的语言很多我不大熟悉,就不瞎掰了。

版本管理工具

有些软件本身比较简单,没有做多版本啊升级啊什么的。就有人做了工具,帮助这些工具管理版本。

我自己用过的稍微舒服一点的是基于bash的asdf-vm,支持的工具由插件决定,插件简单说也就三个可执行文件,装什么东西的话读环境变量就行。用asdf可以方便的管理比如说Python的版本啊、Go的版本啊这些东西,最主要的好处是干净。

定义环境变量来加载特定的Shared Object

Linux可以动态定义加载so的路径,从而一定程度上缓解不同版本so带来的问题。比如说我们在老版本系统上动态编译了一个程序,更新了新系统然后这玩意儿加载新的库以后不干活儿了,可以想办法编译老版本的库、放到和新系统以后通过LD_LIBRARY_PATH或者LD_PRELOAD加载自己编译的老版本的库。

但是这个方法用不好会砸到自己的脚,所以最好不要轻易使用。有篇博客干脆起名LD_LIBRARY_PATH – or: How to get yourself into trouble!