locez 发布的文章

原文观点

今日 Linux 中国发布了一篇文章 《大家都在点赞 Windows Terminal,我决定给你泼一盆冷水》 。该文主要观点引用如下:

  • Windows Terminal 是一个套在 Windows 操作系统原本的 CMD、Powershell、Windows Subsystem for Linux(WSL)之上的一个界面更加漂亮、功能更加强大的终端工具。严格来说,它是套在 CMD 、Powershell 之上的一个终端。
  • 它也只是一个终端而已,而不是一个更加好用的 Shell。
  • Windows 用户所吐槽的命令行不好用不在于其表面,而在于其没有一个足够好用的 Shell。
  • 看起来,Windows Terminal 和 WSL 的结合,已经非常完美了,但作为一个 Shell 来用的话,又显的过于笨重。
  • WSL 无论做的再怎么好,无法摆脱它只是一个运行于 Windows 系统中附属的子系统。无论 WSL 做的再好,本质上并没有比虚拟机做的更多。
  • 作为生态的打造者,微软真正可以做好的是,打造一个能够在体验和生态上与 Unix Shell 一致的 Shell,或者是干脆提供 Bash、Zsh 等常用 Shell 的原生支持(WSL 虽然支持 Bash、Zsh等,但依然是需要先进入 WSL 才能使用,但你可以畅想一下,如果 CMD 变成了 Bash,会是什么样的呢?)。
  • 对于广大使用 Windows 开发的用户来说,一个闪闪发亮的、现代化的、功能强大的终端固然很好,但好的终端只不过是锦上添花之举,而一个强大好用的 Shell 才是真正能够雪中送炭的东西,只有一个足够好用的 Shell,才能成为 Windows 命令行世界的救世主。

关于原文更完整的观点,请参阅原文。这里针对原文观点和表达一些不同意见的商榷。

Terminal 与 Shell

诚如原文所说,Windows Terminal 其实是一个窗口而已,真正执行的是里面的软件,但是 Windows Terminal 并不如原文说的那么一无是处。众所周知 CMD、PowerShell 默认进入以后是没有标签的,想要使用多个只能多开窗口,管理起来不如够方便,而且配色也是影响使用者快速定位问题的一个重要指标。而这次的 Windows Terminal 不但解决这些问题,还能够支持 emoji,可大大提升在里面所运行的程序的使用体验。

再来说说什么是 shell ?一个 shell 是提供用户与操作系统交互的界面/入口,当我们在命令行中输入各种命令时,其实就是在执行一个应用程序,shell 将这些程序送往内核进行执行,所以最终还是要归到内核的系统调用,此外广义上的 shell 其实还包括了图形界面。

让我们来看看第一个点:

  • Windows Terminal 是一个套在 Windows 操作系统原本的 CMD、Powershell、Windows Subsystem for Linux(WSL)之上的一个界面更加漂亮、功能更加强大的终端工具。严格来说,它是套在 CMD 、Powershell 之上的一个终端。

Windows Terminal 准确来说就是一个支持配色的更加现代的终端入口,也不能说是嵌套什么 CMD、PowerShell、WSL,你想怎么使用它取决于你想进入什么样的命令行解释器。举个 Linux 下的例子就是我可以在 konsole 下使用 fish、zsh、bash 等 shell 解释器。

更好用的 shell?

  • 它也只是一个终端而已,而不是一个更加好用的 Shell。
  • Windows 用户所吐槽的命令行不好用不在于其表面,而在于其没有一个足够好用的 Shell。
  • 看起来,Windows Terminal 和 WSL 的结合,已经非常完美了,但作为一个 Shell 来用的话,又显的过于笨重。

关于这里,我觉得原文作者忽视了 Shell 与 Terminal 的区别。Shell 作为一个命令解释器,必然有自己的语法。而 Linux 生态系统中已经很好用的 shell 就有 fish、zsh、bash 等,但是这些语法也不是所有都兼容的,而且一个好用的 shell 一般只是用户感觉上的东西,没有很明确的指标。Windows 用户在有了 WSL 之后可以使用任何 Linux 已经有的 shell 解释器,这其实已经足够解决问题了,毕竟这些工具的改进是为了吸引 Linux 平台上的开发者,而不是为了一个毫无经验的小白准备的。

此外,原文作者提到的 Windows Terminal 与 WSL(搭载完整内核) 结合作为 shell 使用的话,无异于高射炮打蚊子。这点我也是强烈反对的,首先 shell 只是一个命令解释器,它其实不负责命令的执行,最终所有的程序都要传递给系统调用,如果底层的系统调用不支持,那么该 shell 脚本也是无法执行的(内核不会有反应、或者报错),所以你要使用 shell,那么必须要求有底层内核的支持,这不是什么高射炮打不打蚊子的事,而是你必须要知道其实 shell 它自己本身就是个解释器,没有别的特异功能而已。

一个更好用的 shell 也许是值得吸引人的,但是其实 shell 的语法也不见得多好用,很多反人类的,只是我们已经学习接受了这种语法所以认可它。另一个方面是历史问题,要想你写的脚本一次编写处处执行,那么最好就是 bash 兼容了,否则别人为了执行你的特殊语法,还要装一个能读懂你的 shell 语法的解释器。

wsl 与虚拟机?

  • WSL 无论做的再怎么好,无法摆脱它只是一个运行于 Windows 系统中附属的子系统。无论 WSL 做的再好,本质上并没有比虚拟机做的更多。

我其实觉得这句话没有道理,为什么这样说呢,确实 WSL 不会比虚拟机做的更多,因为你虚拟机安装的是一个完整的操作系统,但是 WSL 优势是什么?

WSL 的优势就是不需要虚拟机,你便可以使用大部分 Linux 的生态,这是向开发人员示好。而且 WSL 不需要长期运行一个虚拟机,在 WSL1 的时候,你实际执行应用 WSL 会把系统调用转成 NT 系统调用。而 WSL2 将包含完整 Linux 内核,还将支持 Docker(此处无法得知它具体的实现,不做推测)。WSL1 的限制很多,使用起来不是特别方便,这个有使用过的朋友应该很有体会,但是 WSL2 既然能运行 Docker,那么有了 Docker 我就有了一切。

生态体验?

  • 作为生态的打造者,微软真正可以做好的是,打造一个能够在体验和生态上与 Unix Shell 一致的 Shell,或者是干脆提供 Bash、Zsh 等常用 Shell 的原生支持(WSL 虽然支持 Bash、Zsh等,但依然是需要先进入 WSL 才能使用,但你可以畅想一下,如果 CMD 变成了 Bash,会是什么样的呢?)。
  • 对于广大使用 Windows 开发的用户来说,一个闪闪发亮的、现代化的、功能强大的终端固然很好,但好的终端只不过是锦上添花之举,而一个强大好用的 Shell 才是真正能够雪中送炭的东西,只有一个足够好用的 Shell,才能成为 Windows 命令行世界的救世主。

这两个观点也是不攻自破的,我既然可以使用 WSL,那么我本身就拥有了 Linux 的生态。如果是希望写 bat 批处理而能有 bash、zsh 的这些体验,那么确实是需要一个新的 shell 满足 Unix Shell 语法,再来解释 Windows 下的命令行,可是这其实也是不需要的。因为本人发现在 WSL 里面执行一个 exe 程序是完全可行的,因此可以用这种 shell 语法去编写我的脚本,oh nice!!体验非常统一啊有没有?

locez@Lenovo-PC~> pycharm64.exe  ### 会启动我的 pycharm
locez@Lenovo-PC~> git.exe | xargs echo

我的观点

我本人认为,微软的这些拥抱 Linux 的举措,其实就是在吸引 Linux 上的开发者而已,开发者想要的工具,如果能够在 Windows 下就能直接使用,那对我们这些开发人员来说无外乎是喜报。工具多一个总不是坏事,但是如果它真的值得使用,那么用户一定会增加,这就是需要微软来做的事情了。我本人是双系统用户,在打游戏娱乐方面我一定会使用 Windows,做开发写代码我会切换到 Linux,曾经写一个很小的软件也是如此。但是后来 WSL 出现了,简单的脚本我可以在 Windows 下就直接完成并且提交,不需要重启系统,然后继续玩我的游戏,美滋滋。

另外就是 Windows Terminal 与 WSL2 的出现会解放我现在系统上的一些工具,例如 git bash、gpg4win 等。如果 WSL2 真的有完整的系统调用,那么我现有的 Windows 上的开发环境便不再需要,专注于游戏娱乐,但是一进 WSL 便是我工作学习的地方。

摘要

在 Linux 的日常使用中,我们经常需要修改一些配置文件,然而在软件升级以后,经常会面临配置更新后与原配置部分不兼容的问题(当然我们更多的可能是来制作软件升级的补丁)。在这种情况下我们通常有两种选择:

  • 对比现有配置,手动在新配置文件中改动
  • 利用 sedawk 等工具配合改动
  • 采用 diffpatch 制作增量补丁的方式改动

本文主要通过一个升级awesome 配置的例子,对第三种方法进行介绍和讲解。

diff 介绍

diff 是一个文件比较工具,可以逐行比较两个文件的不同,其中它有三种输出方式,分别是 normalcontext 以及 unified。区别如下:

  • normal 方式为默认输出方式,不需要加任何参数
  • context 相较于 normal 模式的简单输出,contetx 模式会输出修改过部分的上下文,默认是前后 3 行。使用参数 -c
  • unified 合并上下文模式则为新的上下文输出模式,同样为前后 3 行,只不过把上下文合并了显示了。使用参数 -u

:本文主要介绍 unified 模式

其他常用参数:

  • -r 递归处理目录
  • -N 将缺失的文件当作空白文件处理

diff 语法与文件格式

diff [options] old new

先来看一个简单的例子:

$ cat test1 
linux
linux
linux
linux
$ cat test2
locez
linux
locez
linux

此时输入 diff -urN test1 test2 会输出以下信息:

--- test1   2018-05-12 18:39:41.508375114 +0800
+++ test2   2018-05-12 18:41:00.124031736 +0800
@@ -1,4 +1,4 @@
+locez
 linux
-linux
-linux
+locez
 linux

先看前面 2 行,这两行为文件的基本信息,--- 开头为改变前的文件,+++ 开头为更新后的文件。

--- test1   2018-05-12 18:39:41.508375114 +0800
+++ test2   2018-05-12 18:41:00.124031736 +0800

第三行为上下文描述块,其中 -1,4 为旧文件的 4 行上下文,+1,4 为新文件的:

@@ -1,4 +1,4 @@

而具体到块里面的内容,前面有 - 号的则为删除,有 + 号为新增,不带符号则未做改变,仅仅是上下文输出。

patch 介绍

patch 是一个可以将 diff 生成的补丁应用到源文件,生成一个打过补丁版本的文件。语法:

patch [oiption] [originalfile [patchfile]]

常用参数:

  • -i 指定补丁文件
  • -pNumdiff 生成的补丁中,第一二行是文件信息,其中文件名是可以包含路径的,例如 --- /tmp/test1 2018-05-12 18:39:41.508375114 +0800 其中 -p0 代表完整的路径 /tmp/test1,而 -p1 则指 tmp/test1-pN 依此类推
  • -E 删除应用补丁后为空文件的文件
  • -o 输出到一个文件而不是直接覆盖文件

应用

awesome 桌面 3.5 与 4.0 之间的升级是不兼容的,所以在升级完 4.0 以后,awesome 桌面部分功能无法使用,因此需要迁移到新配置,接下来则应用 diffpatch 实现迁移,当然你也可以单纯使用 diff 找出不同,然后手动修改新配置。

现在有以下几个文件:

  • rc.lua.3.5 3.5 版本的默认配置文件,未修改
  • rc.lua.myconfig 基于 3.5 版本的个人配置文件
  • rc.lua.4.2 4.2 新默认配置,未修改

思路为利用 diff 提取出个人配置与 3.5 默认配置文件的增量补丁,然后把补丁应用在 4.2 的文件上实现迁移。

制作补丁

$ diff -urN rc.lua.3.5 rc.lua.myconfig  > mypatch.patch

应用补丁

$ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
patching file rc.lua (read from rc.lua.4.2)
Hunk #1 FAILED at 38.
Hunk #2 FAILED at 55.
Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
2 out of 4 hunks FAILED -- saving rejects to file rc.lua.rej

显然应用没有完全成功,其中在 38 行以及 55 行应用失败,并记录在 rc.lua.rej 里。

$ cat rc.lua.rej 
--- rc.lua.3.5  2018-05-12 19:15:54.922286085 +0800
+++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
@@ -38,10 +38,10 @@

 -- {{{ Variable definitions
 -- Themes define colours, icons, font and wallpapers.
-beautiful.init("@AWESOME_THEMES_PATH@/default/theme.lua")
+beautiful.init("~/.config/awesome/default/theme.lua")

 -- This is used later as the default terminal and editor to run.
-terminal = "xterm"
+terminal = "xfce4-terminal"
 editor = os.getenv("EDITOR") or "nano"
 editor_cmd = terminal .. " -e " .. editor

@@ -55,18 +55,18 @@
 -- Table of layouts to cover with awful.layout.inc, order matters.
 local layouts =
 {
-    awful.layout.suit.floating,
-    awful.layout.suit.tile,
-    awful.layout.suit.tile.left,
-    awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
+--    awful.layout.suit.floating,
+--    awful.layout.suit.tile,
+--    awful.layout.suit.tile.left,
+--    awful.layout.suit.tile.bottom,
+--    awful.layout.suit.tile.top,
     awful.layout.suit.fair,
     awful.layout.suit.fair.horizontal,
     awful.layout.suit.spiral,
     awful.layout.suit.spiral.dwindle,
     awful.layout.suit.max,
     awful.layout.suit.max.fullscreen,
-    awful.layout.suit.magnifier
+--    awful.layout.suit.magnifier
 }
 -- }}}

这里是主题,终端,以及常用布局的个人设置。

修正补丁

再次通过对比补丁文件与 4.2 文件,发现 38 行区块是要删除的东西不匹配,而 55 行区块则是上下文与要删除的内容均不匹配,导致不能应用补丁,于是手动修改补丁

$ vim mypatch.patch
--- rc.lua.3.5  2018-05-12 19:15:54.922286085 +0800
+++ rc.lua.myconfig 2018-05-12 19:13:35.057911463 +0800
@@ -38,10 +38,10 @@

 -- {{{ Variable definitions
 -- Themes define colours, icons, font and wallpapers.
-beautiful.init(gears.filesystem.get_themes_dir() .. "default/theme.lua")
+beautiful.init("~/.config/awesome/default/theme.lua")

 -- This is used later as the default terminal and editor to run.
-terminal = "xterm"
+terminal = "xfce4-terminal"
 editor = os.getenv("EDITOR") or "nano"
 editor_cmd = terminal .. " -e " .. editor

@@ -55,18 +55,18 @@

 -- Table of layouts to cover with awful.layout.inc, order matters.
 awful.layout.layouts = {
-    awful.layout.suit.floating,
-    awful.layout.suit.tile,
-    awful.layout.suit.tile.left,
-    awful.layout.suit.tile.bottom,
-    awful.layout.suit.tile.top,
+--    awful.layout.suit.floating,
+--    awful.layout.suit.tile,
+--    awful.layout.suit.tile.left,
+--    awful.layout.suit.tile.bottom,
+--    awful.layout.suit.tile.top,
     awful.layout.suit.fair,
     awful.layout.suit.fair.horizontal,
     awful.layout.suit.spiral,
     awful.layout.suit.spiral.dwindle,
     awful.layout.suit.max,
     awful.layout.suit.max.fullscreen,
-    awful.layout.suit.magnifier,
+--    awful.layout.suit.magnifier,
     awful.layout.suit.corner.nw,
     -- awful.layout.suit.corner.ne,
     -- awful.layout.suit.corner.sw,
....
....

输出省略显示,有兴趣的读者可以仔细与rc.lua.rej 文件对比,看看笔者是怎样改的。

再次应用补丁

$ patch rc.lua.4.2 -i mypatch.patch -o rc.lua
patching file rc.lua (read from rc.lua.4.2)
Hunk #1 succeeded at 41 (offset 3 lines).
Hunk #2 succeeded at 57 with fuzz 2 (offset 2 lines).
Hunk #3 succeeded at 101 with fuzz 1 (offset 5 lines).
Hunk #4 succeeded at 276 with fuzz 2 (offset 29 lines).
$ cp rc.lua ~/.config/awesome/rc.lua  ### 打完补丁直接使用

总结

diffpatch 配合使用,能当增量备份,而且还可以将补丁分发给他人使用,而且在日常的软件包打补丁也具有重要的意义,特别是内核补丁或者一些驱动补丁,打补丁遇到错误时候可以尝试自己修改,已满足自身特殊要求,修改的时候一定要抓住 2 个非常重要的要素:

  1. 要修改的内容是否匹配?特别是要删除的
  2. 上下文是否满足,特别是距离要修改的地方前后一行,以及上下文的行数是否满足,默认是 3 行上下文

docker

之前的文章中我们提到可以通过容器创建一个我们自定义过的镜像,那么我们是否可以直接通过基础的镜像直接自定义镜像呢?答案当然是可以的,在 Docker 中我们可以从名为 Dockerfile 的文件中读取指令并且自动构建镜像。在本文中,将介绍 Dockerfile 的基本语法以及基本知识。

1、Dockerfile 是什么?

Dockerfile 其实是一份文本文档,里面包含了用户可以用来操作镜像的一些指令。通过顺序执行这些指令,最后得到一个自定义的镜像,这有点类似于我们的 shell 脚本。

2、Dockerfile 示例

接下来先看一个 Dockerfile 示例:

FROM centos
LABEL maintainer="Locez <[email protected]>"
ENV TEST="This is a test env"
COPY nginx.repo /etc/yum.repos.d/nginx.repo
RUN yum update -y && \
        yum install -y nginx
COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /usr/share/nginx/html/index.html
COPY index_files/ /usr/share/nginx/html/index_files/
EXPOSE 80
CMD ["/usr/sbin/nginx","-g","daemon off;"]

在上面我们可以看到 Dockerfile 中的一些指令,通过名称我们也可以猜到这些指令大概是干嘛的,其中有一些对文件的操作,因此我们先来看看用于存放 Dockerfile 的这个目录的目录结构:

# tree .
.
├── Dockerfile
├── index_files
│   ├── 145049z4og8xyjhx4xy8go.jpg
│   ├── 222746e5vh38d7ey3leyps.jpg
│   ├── 88x31.png
│   ├── archlinux-splash.png
│   ├── bdshare.css
│   ├── Best-Linux-Markdown-Editors.png
│   ├── core.js
│   ├── docker-icon.jpg
│   ├── hadoop-pic1.png
│   ├── jquery_002.js
│   ├── jquery.css
│   ├── jquery.js
│   ├── MathJax.js
│   ├── pic.gif
│   ├── raspberrypiraspberry-pi-logo.jpg
│   ├── script.js
│   ├── scrollup.png
│   ├── share.js
│   ├── style.css
│   └── z_stat.js
├── index.html
├── nginx.conf
└── nginx.repo

1 directory, 24 files

构建镜像

在当前目录下执行以下命令构建镜像:

# docker build -t locez/nginx .
Sending build context to Docker daemon 1.851 MB
Step 1/10 : FROM centos
 ---> 196e0ce0c9fb
Step 2/10 : LABEL maintainer "Locez <[email protected]>"
 ---> Using cache
 ---> 9bba3042bcdb
Step 3/10 : ENV TEST "This is a test env"
 ---> Using cache
 ---> c0ffe95ea0c5
Step 4/10 : COPY nginx.repo /etc/yum.repos.d/nginx.repo
 ---> Using cache
 ---> bb6ee4c30d56
Step 5/10 : RUN yum update -y &&        yum install -y nginx
 ---> Using cache
 ---> 6d46b41099c3
Step 6/10 : COPY nginx.conf /etc/nginx/nginx.conf
 ---> Using cache
 ---> cfe908390aae
Step 7/10 : COPY index.html /usr/share/nginx/html/index.html
 ---> Using cache
 ---> 21729476079d
Step 8/10 : COPY index_files/ /usr/share/nginx/html/index_files/
 ---> Using cache
 ---> 662f06ec7b46
Step 9/10 : EXPOSE 80
 ---> Using cache
 ---> 30db5a889d0a
Step 10/10 : CMD /usr/sbin/nginx -g daemon off;
 ---> Using cache
 ---> d29b9d4036d2
Successfully built d29b9d4036d2

然后用该镜像启动容器:

# docker run -d -it --rm --name test-nginx -p 8080:80 locez/nginx
e06fd991ca1b202e08cf1578f8046355fcbba10dd9a90e11d43282f3a1e36d29

用浏览器访问 http://localhost:8080/ 即可看到部署的内容。

3 Dockerfile 指令解释

Dockerfile 支持 FROMRUNCMDLABELEXPOSEENVADDCOPYENTRYPOINTVOLUMEUSERWORKDIRARGONBUILDSHELL 等指令,这里只选择常用的几个进行讲解,可结合上面的示例进行理解。其它的请自行查阅官方文档。

3.1 FROM

FROM 指令用于指定要操作的基础镜像,因为在我们构建我们自己的镜像的时候需要一个基础镜像。 语法:

FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]

其中 [AS <name>] 为指定一个名称,在一个 Dockerfile 中多次使用 FROM 时如有需要,可用 COPY --from=<name|index> 语法进行复制。

3.2 RUN

RUN 指令用于执行命令,并且是在新的一层上执行,并把执行后的结果提交,也就是生成新的一层。基于这个问题,我们在使用 RUN 指令时应该尽可能的把要执行的命令一次写完,以减少最后生成的镜像的层数。 语法:

RUN <command>
RUN ["executable", "param1", "param2"]

3.3 CMD

CMD 指令用于给容器启动时指定一个用于执行的命令,例如上例中的 nginx 启动命令。 语法:

CMD ["executable","param1","param2"]
CMD ["param1","param2"] ### 用于给 ENTRYPOINT 指令提供默认参数
CMD command param1 param2

3.4 LABEL

LABEL 指令用于为镜像指定标签,可用 docker inspect 命令查看。可用来代替被舍弃的 MAINTAINER 命令。 语法:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

3.5 EXPOSE

EXPOSE 指令用于告诉 Docker 容器监听的特殊端口,但是此时端口还没有暴露给 host ,只有当在运行一个容器显式用参数 -p 或者 -P 的时候才会暴露端口。 语法:

EXPOSE <port> [<port>/<protocol>...]

3.6 ENV

ENV 指令用于设定环境变量。 语法:

ENV <key> <value>
ENV <key>=<value> ...

3.7 ADD

ADD 指令用于复制新文件,目录,远程文件到容器中。其中 <src> 可以为文件,目录,URL,若为可解压文件,在复制后会解压。 语法:

ADD <src>... <dest>
ADD ["<src>",... "<dest>"]

3.8 COPY

COPY 指令与 ADD 指令非常相似,但 COPY 比较直观且简单,它只支持本地的文件以及目录的复制,不像 ADD 指令可以远程获取文件并解压。 语法:

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

3.9 ENTRYPOINT

ENTRYPOINT 指令也跟 CMD 指令相似,用于指定容器启动时执行的命令。当使用 ENTRYPOINT 指令时,可用 CMD 命令配合,这样在启动容器时,可以对 CMD 指令写入的参数进行覆盖。 语法:

ENTRYPOINT ["executable", "param1", "param2"]

例子:

ENTRYPOINT ["top","-b"]
CMD ["-c"]

上面的 -c 参数可以在启动时覆盖 docker run -it --rm --name test top -H。 如果要覆盖 ENTRYPOINT 指令则用 --entrypoint 参数启动容器。

3.10 VOLUME

VOLUME 指令用于为容器创建一个挂载点,这个挂载点可以用来挂载 本地文件/文件夹 也可以用来挂载 数据卷。其中若在启动一个新容器时没有指定挂载目录,则会自动创建一个数据卷,当容器被销毁时,数据卷如果没有被其它容器引用则会被删除。 语法:

VOLUME ["/data1","/data2"]

3.11 USER

USER 指令用于设置执行 RUN, CMD, ENTRYPOINT 等指令的用户以及用户组。默认为 root 用户。 语法:

USER <user>[:<group>]

3.12 WORKDIR

WORKDIR 指令用于设置 RUN, CMD, ENTRYPOINT, COPY, ADD 等指令的工作目录。 语法:

WORKDIR /path/to/workdir

4 总结


本文从一个具体的例子出发,讲述了如何利用 Dockerfile 构建镜像,然后解释了 Dockerfile 文件中的指令的语法,有关更多内容可访问官方文档。

5 参考资料


Linux 由于开源,所以具备可定制性,因此衍生了许多发行版。Ubuntu 和 Fedora 算是其中对新手比较友好的两个发行版,主要是其安装较为简单,用户群多,有问题搜索出相关的信息或者找前辈解决。此文为 Linux 新手准备,通过展示整个安装过程来使 Linxu 新手完成安装 Ubuntu 或 Fedora ,也恳请各位前辈指出不足之处。

阅读建议

  • 本文将包含 Ubuntu 和 Fedora 两个发行版的安装,请先通篇浏览全文,再决定安装哪个发行版,并且配图有相应的文字说明,请不要忽视。
  • 如果你是一位新手,强烈建议使用虚拟机操作;如果你相信自己可以解决问题,也可使用 ultraisoUSBWriterdd命令写入 U 盘,进行实体机安装,此处不详述。
  • 有任何问题都可以加入 Linux中国-新手村 QQ 群提问,QQ 群号 198889109 ,验证信息 LINUX

Ubuntu 简介

Ubuntu 是一个基于 Debian 的 GNU/Linux 操作系统,支持 X86 、64以及 PPC 架构。Ubuntu 每隔六个月发布一个版本,即每年的四月和十月,本文使用的是 15.04 64-bit 版本。Ubuntu 对于新手应该是比较友好的一个 Linux 发行版,中文本地化也做的不错,有开箱即用的感觉。因为 Ubuntu 近几年用户群的增加,多了很多对于新手有用的资料,因此不用担心遇到问题无法解决,善用搜索和提问,将使你更快速地成长。

更多 Ubuntu 的介绍请移步:Ubuntu 17.04 (Zesty Zapus)/Ubuntu 16.04.2 LTS (Xenial Xerus)/Ubuntu 16.04.2 LTS (Xenial Xerus) ") 。

Fedora 简介

Fedora 是一个由 Fedora 社区开发的 Linux 发行版,由 Red Hat 公司赞助。可以将 Fedora 看成是 Red Hat Linux 个人使用的代替,由于有 Red Hat 公司的支持,Fedora 的功能非常完善,还分为 WORKSTATION 、SERVER 和 CLOUD 版本。本文使用的是 Fedora 22 WORKSTATION (工作站),Fedora 22 已经将包管理器从 YUM 改为 DNF ,因此建议学习者直接学习 DNF

更多 Fedora 的介绍请移步:Fedora 27

本文环境

  • 注意本文下载链接直达官方下载,并且不断更新,以使新的 Linux 用户可以用上最新的发行版,且文中的安装步骤基本不因版本的更替而改变。
  • Windows 8.1 64-bit
  • VirtualBox-5.2.4 点此下载
  • Ubuntu 16.04 LTS 64-bit 点此下载
  • Ubuntu 16.04 LTS 32-bit 适合配置较低的用户使用 点此下载
  • Fedora 27 64-bit 点此下载
  • Fedora 25 32-bit 适合配置较低用户使用 点此下载

更多 Linux 发行版的下载,可以看这里:Linux 下载

Ubuntu 安装

1.新建与加载盘片

当你安装完 VirtualBox 后,打开你应该会看到下面这样的界面

VirutalBox

点击新建后会出来如下图所示的界面,一般如图填写即可,内存可酌情填写

新建虚拟电脑

下一步将创建虚拟硬盘,如图所示,默认位置为 C 盘,如果你不想在 C 盘创建,请确保你选择的盘格式为NTFS

创建虚拟硬盘

创建完成后,请点 设置 如图加载 ISO 文件

加载 ISO 文件

2.安装 Ubuntu

点击启动 ,会开机,进入如下界面

开始安装

安装选项

这里请注意,如果你与笔者一样使用虚拟机,强烈建议选择 清除整个磁盘并安装 Ubuntu ,但如果你要装到实体机与 Windows 形成双系统时,请选择 其他选项 ,但这要求你对 Linxu 有一定的了解且具备一定的基础进行分区操作,注意不要覆盖 Windows 的 C 盘,此处由于篇幅原因,不再详述。

安装类型

如图,进行用户设定,计算机名 是主机名,用户名 是登录时用的账户名称,密码 则是你所设 用户名 的登录密码,请务必记牢。

添加用户

这一步之后会选择时区,直接点下一步即可,键盘选择如下图

选择键盘布局

配置选择已完成,接下来请耐心等待安装过程,如图,请不要点击 SKIP

安装中

耐心等待安装完成,然后会重启进入系统,用你上面配置的用户名和密码登录,请注意最好不要登录 root ,你可以用 sudo 命令来获取相应的权限,下图是展示成果:

安装完成

Fedora 安装

1.新建与加载盘片

请参考上面的 Ubuntu 部分。

2.安装 Fedora

点击 启动,会开机,进入如下界面,如图操作

开始安装

接下来依然是如图操作

安装到硬盘

然后是选择语言,选择完后进入如图界面

安装信息摘要

配置安装位置,这里请注意,如果你与笔者一样使用虚拟机,强烈建议选择 自动配置分区 ;但如果你要装到实体机与 Windows 形成双系统时,请选择 我要配置分区 ,但这要求你对 Linxu 有一定的了解且具备一定的基础进行分区操作,注意不要覆盖 Windows 的 C 盘,此处由于篇幅原因,不再详述。

选择安装目标

下一步将创建 root日常使用账户root 账户有最大的管理权限,你甚至可以将整个系统删除,所以使用 root 账户请务必小心,日常使用账户 应作为你的习惯使用账户,必要时只需使用 sudo 命令暂时提升权限即可,更多说明如图所示

创建用户和密码

root 配置只需创建密码即可,下图是 日常使用账户 配置

创建用户

配置完后将回到之前的界面,请耐心等待安装,如图

安装中

安装完成,点击 退出 后,进入的依然是 Live CD 环境,请先关机,再执行下一步

安装完成,退出关机

由于 Fedora 未自动卸载盘片,因此需要手动卸载盘片,否则将再次进入 Live CD 环境,请如图操作

卸载盘片

接下来则是点击 启动 进入你的 Fedora ,使用你上面设置的用户名和密码登录,请注意最好不要登录 root ,你可以用 sudo 命令来获取相应的权限,下图是展示成果

安装成功

参考资料


新进入 Linux 世界的朋友们,也许你已经下载好了 Linux 的安装 ISO,并且安装好了你的 Linux ,那么接下来,你也许希望安装一些 Linux 上用的软件。开始你可能会使用图形界面的软件中心来安装,有时候也需要使用命令行来安装,或者甚至需要自己去编译一个二进制出来——这是多么神奇的一件事啊。

那么我们今天就讲一讲如何在 Linux 上安装软件包。

本文将从 GUI 软件中心包管理器在线仓库安装本地安装源码安装 一一为你讲解有关安装软件包需要注意的事项。

本文环境

  • Ubuntu 15.04 64-bit
  • Fedora 22 64-bit

安装目标

  • wget 它是一个用于从网络上下载文件的简单自由软件,在下文我们也会用到 wget 进行下载某些文件。

相关概念

  • :我们安装程序可以从 远程仓库本地仓库 获取,这个 仓库 就是我们程序的来源,因此可以称为
  • 包管理器 :顾名思义 包管理器 是用来管理软件包的,用这个工具我们可以轻松的从仓库中安装、卸载程序。不同的发行版有不同的包管理器,Ubuntu 使用 apt-get 而 Fedora 22使用 dnf
  • 源码 : 程序的原始代码,未经过编译,通过编译源码也可以生成程序。

图形界面的软件中心

Ubuntu 软件中心

当我们处于图形界面( GUI :Graphical User Interface) 时,Ubuntu 为我们提供了一个图形界面的安装工具,称为 Ubuntu 软件中心,通过这个软件中心,我们可以像 Windows 一样通过点击几个按钮,轻松实现软件包安装。下图为打开软件中心之后的图,左边是一些分类,下面则是一些推荐的软件包。

Ubunutu 软件中心

点击已安装可以查看安装在本机的软件包,并且可以在此管理它们,如图选中 Firefox 并点击卸载,此时会提示你输入密码,输入完成且正确就会卸载你所选的程序。

已安装

接下来在搜索框搜索 wget 你可以看到如图所示的东西,并且只需点击安装并正确输入密码即可。

安装新程序

Fedora 软件中心

点开如图所示的图标就可以打开 Fedora 的软件中心。

Fedora 软件中心

打开后界面如图,分类在最下面

软件中心

点开上图的扫雷,显示如下,点击 安装 ,静候即可

安装新程序

现在转到 已安装 ,我们可以看到刚刚安装的扫雷,点击 移除 ,就可以删除了。

移除程序

如果你遇到下图,只需要输入你的密码即可。

认证

使用包管理器安装

1.换源

发行版换源方法
Ubuntu阿里云镜像配置请参考这里
USTC镜像配置请参考这里
Fedora阿里云镜像配置请参考这里
USTC镜像配置请参考这里

换源是为了提升下载速度,上文的概念已经提到了,我们安装软件是从远程仓库下载安装的,自然这个远程仓库的网络连通必须要好,并且下载速度要可观。

2.更新源

更换了源的文件后,还需要更新本地数据库信息,以便与远程仓库信息一致。

发行版包管理工具参数示例解释
Ubuntuapt-getupdatesudo apt-get update取回更新的软件包列表信息
Fedoradnfcheck-updatesudo dnf check-update取回更新的软件包列表信息

3.安装软件包

发行版包管理工具类型参数示例解释
Ubuntuapt-get远程仓库installsudo apt-get install packagename安装软件包
Fedoradnf远程仓库installsudo dnf install packagename安装软件包
Ubuntudpkg本地deb包-isudo dpkg -i filename.deb安装本地二进制deb包
Fedorarpm本地rpm包-isudo rpm -i filename.rpm安装本地二进制rpm包

4.卸载软件包

发行版包管理工具参数示例解释
Ubuntuapt-getremovesudo apt-get remove packagename卸载软件包
Fedoradnfremovesudo dnf remove packagename卸载软件包
Ubuntudpkg-rsudo dpkg -r packagename卸载软件包

5.升级所有软件包

发行版包管理工具参数示例解释
Ubuntuapt-getupgradesudo apt-get upgrade升级所有软件包
Fedoradnfupgradesudo dnf upgrade升级所有软件包

6.其它参数

发行版包管理工具参数示例解释
Ubuntuapt-getpurgesudo apt-get purge packagename卸载并清除软件包的配置
sourceapt-get source packagename下载源码包文件
cleansudo apt-get clean删除所有已下载的包文件
downloadapt-get download packagename下载指定的二进制包到当前目录
--helpapt-get --help获取帮助
Fedoradnfcleansudo dnf clean清除旧缓存
makecachesudo dnf makecache生成新缓存
-hdnf -h获取帮助

从源码编译安装

有些时候我们会发现有的软件包并没有包含在软件仓库中,也没有可用的二进制包,这时候我们可以尝试从源码编译安装,我在此处仍以wget 为例,示范如何编译,并解决编译遇到的问题

以下环境为 Ubuntu 15.04

$ mkdir buildwget #构建目录
$ cd buildwget
$ wget http://ftp.gnu.org/gnu/wget/wget-1.16.tar.xz         #下载源码包
$ sudo apt-get remove wget  #为了后面的测试,先把 wget 卸载了
$ xz -d wget-1.16.tar.xz  #解压 xz 文件
$ tar -xvf wget-1.16.tar #解档 tar 文件
$ cd wget-1.16
$ ls                     #列出文件
ABOUT-NLS   ChangeLog.README  GNUmakefile   maint.mk     po       util
aclocal.m4  configure         INSTALL       Makefile.am  README
AUTHORS     configure.ac      lib           Makefile.in  src
build-aux   COPYING           m4            msdos        testenv
ChangeLog   doc               MAILING-LIST  NEWS         tests

上面的文件就是我们将要编译的源文件,其中有个特别要注意的就是 INSTALL,我们要养成一个习惯,多看 INSTALL 文件,这个文件会告诉我们怎么编译,编译时需要注意什么?但由于此处的编译较简单,所以 INSTALL 也没有提到什么特别重要的事情。

按照 INSTALL 我们先执行 ./configure

$ ./configure

如果出现如下的错误

configure: error: --with-ssl=gnutls was given, but GNUTLS is not available.

错误提示说,给定的 SSLgnutls 但是却不可用(因为没有安装),因此我们安装并指定 opensslwgetSSL

$ sudo apt-get install openssl 
$ sudo apt-get install libssl-dev
$ ./configure --with-ssl=openssl

如果没有问题,执行完后应该显示如下

configure: Summary of build options:

  Version:           1.16
  Host OS:           linux-gnu
  Install prefix:    /usr/local
  Compiler:          gcc
  CFlags:            -g -O2 
  LDFlags:           
  Libs:              -lssl -lcrypto -ldl -lz 
  SSL:               openssl
  Zlib:              yes
  PSL:               no
  Digest:            yes
  NTLM:              yes
  OPIE:              yes
  Debugging:         yes

然后进行编译

$ make

会输出很多编译信息,不要担心,如果最后没有报错而停止,则编译成功,接下来进行安装

$ sudo make install

试试是不是 wget 命令又出来了?源码安装遇到问题,我们要善于搜索,提问和解决,根据报错内容进行相应的编译调整,缺少的依赖装上,一般就可以成功。

总结

本文主要为新手讲解了 UbuntuFedora 安装软件包的一些方法, 相较之前的版本,本次更改由繁化简,并且以表格的形式给出参数和命令,要熟练和体会这些命令到底是干嘛的,还必须亲自敲一敲,去理解这个命令的作用。从源码编译安装,则展示了一个遇到问题,解决问题的过程,由于编译 wget 较简单,此处也未遇到特别难处理的问题,但这清晰的展示了一个编译安装的过程,遇到错误,我们不要害怕,而要认真阅读给出的错误信息,借此搜索,提问,寻求解答。另外 Linux 下遇到问题首先要自己善于去搜索,提问,解决问题得到答案并归纳总结,不然是很难学到知识的。

UPDATE: 2015-08-31

QQ 6.3 由于版本低,已不能登录,以下教程已不适用,有想要折腾 wine QQ 的仅供参考。

Linux 上面玩 QQ 一直都是一个问题。Wine 算是一个解决方案,但是也有不少人失败了。由于 QQ 的特殊性,采取了一系列的保护措施,导致 QQ 这个 Windows 程序非常复杂,因此 Wine 在运行 QQ 时表现差强人意。本文将要安装的是 QQ6.3 ,更高的版本除非对 QQ 做出修改,否则很难安装成功,即使成功了,问题也挺多的(笔者已试验过 QQ7.4 安装)。写这个的目的主要是方便有人遇到问题截图提问,毕竟 Linux 的普及工作还得靠大家,对于日常聊天还是建议使用手机QQ 。

本文环境

  • Arch Linux (其他发行版仅供参考)
  • KDE4 & LXDE & GNOME (其它请自测)

准备工具

  • Wine
  • winetricks

简介

  • Wine 是一个在类 Unix 系统中运行 Microsoft Windows 程序的软件, Wine 的全称是 Wine Is Not Emulator 意为 Wine 不是一个模拟器,它通过 API 转换技术做出 Linux 上对应于 Windows 的函数,从而调用 DLL 运行 Windows 程序。
  • winetricks 是一个 script ,可以用来下载和安装各种在 Wine 运行时需要的部分 DLL 和框架。如 .NETVisual C++ runtime library 或微软和其他公司的闭源程序,使用 winetricks 你可以快速安装某些常用的Windows程序。

步骤

1.安装 Wine

$ sudo pacman -S wine

注意:64 位需启用 multilib 仓库才可安装 Wine ,去掉 [multilib] 及其 Include的 “#”即可

$ sudo nano /etc/pacman.conf

2.安装 winetricks

$ sudo pacman -S winetricks

3.获取 winetricks-zhverb 文件,更多详情请到: winetricks-zh

$ mkdir workforwine
$ cd workforwine
$ wget https://github.com/hillwoodroc/winetricks-zh/raw/master/verb/qq.verb

4.安装 QQ

$ WINEARCH=win32 winetricks qq

接下来是漫长的安装过程,会下载一系列需要的组件,将缓存在 ~/.cache/winetricks ,请耐心等待。或许你还可以试试 winetricks-zhwinetricks-zhwinetricks 的本地化版本,添加了更多国人可能用到的软件。

$ wget https://github.com/hillwoodroc/winetricks-zh/raw/master/winetricks-zh
$ chmod +x winetricks-zh
$ ./winetricks-zh

注意:若你觉得 安装QQ 这一步安装 monogecko 太慢,如下图:

installmono

installingmono

installgecko

根据配图我们可以知道 mono.NET 需要的包,而 gecko 则是 HTML 需要的包,并且 wine 也更建议我们使用我们发行版中的 monogecko 包,这有两个好处,一是更加符合自己的发行版,二是不用为每个 PREFIEX 单独安装,因此可以尝试以下操作,其他发行版仅供参考:

$ rm -rf ~/.wine
$ sudo pacman -S wine-mono
$ sudo pacman -S wine_gecko
$ WINEARCH=win32 winetricks qq

需要注意的几点

  • 请确保你安装有文泉驿字体 sudo pacman -S wqy-microhei
  • winetrickswinetricks-zh 安装的区别仅在于安装目录不同, winetricks 未指定位置时默认 ~/.wine ,而winetricks-zh 则安装QQ至 ~/.local/share/wineprefixes/qq
  • 有任何问题都可以直接删除上面提到的两个文件夹重来。
  • wine 的不稳定性,导致用 winetricks 安装字体有时可以解决,有时不可以,笔者试验了很多次以失败告终,希望有谁解决了可以告诉笔者。

其他解决方案

参考资料