Gentoo Linux practice Notes: Linux basics

前言

这里所说的Linux,具体指 GNU/Linux 操作系统。含义是,含有GNU的系统+Linux内核,不管GNU的含量有多少,只要有GNU的存在,并且内核是Linux,就是 GNU/Linux 操作系统。

Linux基础分成两个部分介绍,一个是认识Linux,一个是使用Linux。

认识 Linux

即使你成功安装了Gentoo这样难度比较高的Linux发行版,我想,任何时候你都会重新发现一些新的东西。当然,所有的内容都会更新,注意打开页面时的更新提醒。

GNU

GNU's Not Unix!

GNU是一个自由的操作系统,他给予了用户自由,虽然很多Linux用户并不是完全自由的,但是100%的自由,也是GNU的目标。完全自由的操作系统是存在的,完全自由的硬件上运行完全自由的操作系统和软件,这样的情况也是存在的。由于很多时候都是秉行实用主义,我们并不会在意到底是不是GNU的,是不是FSF的,是不是自由的。

但是没有GNU,就没有现在的Linux,没有Linux,就没有现在的GNU系统。GNU的工具和软件包,由于Linux内核的加入,才有了今天坚实的生态基础。

FHS

Linux中,一切皆文件。首先我们需要知道的是文件系统的层次结构标准:FHS, Filesystem Hierarchy Standard。

由于不同操作系统的实现不同,这里具体的实现是最新的Gentoo Baselayout,目前版本:2.8。

路径描述
/整个文件系统层次的根
/bin/单用户模式下的必要命令,一些强大,常用和不常用的工具
/sbin/必要的系统二进制文件,关乎到系统能否正常运行
/dev/设备,以文件的形式
/etc/系统范围的配置文件
/home/用户的家目录
/root/root用户的家目录
/lib//bin/ 和 /sbin/中二进制文件必要的库文件
/usr/unix软件资源,这下面的结构层次与根相同
/usr/local/本地资源,这下面的结构层次与根相同
/var/变量文件
/run/运行中的信息
/tmp/临时文件
/media/可移除的挂载点,如U盘
/mnt/临时挂载的文件系统
/opt/额外的应用

More than FHS

从应用程序的角度,以下路径与环境变量值得关注:

PATH

PATH的一般路径由下面的部分组成,越靠近前面优先级越高。

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin

需要注意的是,与Windows不同,Linux的PATH没有当前目录pwd

LD_LIBRARY_PATH

用于指定查找共享库(动态链接库)时除了默认路径(./lib和./usr/lib)之外的其他路径。

LD_PRELOAD

优先加载的动态链接库

在不同系统上,对于加载动态链接库的处理方式不同,所以很多发行饭LD_开头的环境变量默认是空的。Gentoo对于动态链接库的加载由env-update调用ldconfig更新/etc/ld.so.cache实现。

配置文件

在程序执行时一般会指定加载的配置文件或者含有配置文件的路径,尤其是以daemon的形式被执行时。这些文件一般存放于/etc/${PN},文件名与格式因应用程序而异。

运行时配置文件

在程序运行时一般读取一些运行时的配置文件,或者在真正操作时读取这些运行时的配置。这些配置文件存放的位置一般有这样的顺序:

  • /etc/${PN}rc 或者 /etc/${PN}/${PN}rc
  • '${HOME}/.${PN}rc' 或者 ${HOME}/.config/${PN}
  • 对于免费桌子(Freedesktop)的XDG的规定,有一些配置文件存放于${XDG_CONFIG_DIRS}路径中
运行时变量或文件

这些不属于配置,但是这些变量或者文件对整个系统也起着部分类似于配置的作用,他们一般存放于/var中。

例如,Gentoo的world集合中的软件存放于/var/lib/portage/world,这个文件加上/etc中的配置,一个相同的系统就可以被完全复现了。

临时文件

在Gentoo中,/var/run是指向/run/的软链接,和/tmp/一样都是存放在内存中的tmpfs上的文件。

日志

如果你选择将底裤交给systemd,那么一般的STDOUT或者STDERR都可以被journalctl处理。

更加详细的日志应该存储于/var/log/${PN}中。

包管理器

Linux中的系统文件由包管理器管理,所有的文件都属于一个又一个的包。使用Gentoo,你可能需要尽可能多得学习其他发行版的打包。

常见的包管理器:dpkg,rpm,pacman,portage

常用的包管理器封装:apt与aptitude,yum与dnf,zypper。

dpkg是Debian系的包管理器,而一般使用apt或者aptitude来安装软件。rpm是红帽和SUSE的包管理器,虽然RPM指红帽包管理器,但是SUSE的发行版不属于红帽系。红帽的发行版对rpm的封装有yum和dnf。SUSE对rpm的封装是zypper。pacman可以使用aur helper来帮助构建软件,这是Arch用户量大的原因之一。portage本身不需要额外的封装。

用户与权限: umask

用户组与权限分明,这是Gentoo的一大特点,虽然有些情况下过于Hardened,但也可以认为是Gentoo允许变为加固完善或者完全没有任何加固的一种妥协。

各种UID和GID的定义请参考UID_GID_Assignment_Table

umask分为四个部分:

  • 文件类型
  • 用户权限
  • 组权限
  • 其他用户权限

文件类型:

  1. – : regular file
  2. d : directory
  3. c : character device file
  4. b : block device file
  5. s : local socket file
  6. p : named pipe
  7. l : symbolic link

权限掩码:

数字字母描述
0---无权限
1--x执行
2-w-
3-wx写和执行
4r--
5r-x读和执行
6rw-读和写
7rwx读,写和执行

启动过程

系统上电,进入BIOS,设置基本的硬件,根据引导选项加载boot loader。传统的BIOS可以在可引导的硬盘最开始的一小块分区中检测到boot loader;UEFI则需要通过存储的efivars加载boot loader。

boot loader加载后,如果存initramfs的话,根据设置来启动initramfs,这里为启动Linux内核准备,例如解密磁盘。

initramfs准备好后,执行Linux内核的二进制程序。

Init

Linux启动后,根据init系统来开始运行程序。能够进行下一步,比较重要的是重新挂根的操作,根据/etc/fstab中的设置挂好文件系统。

systemd是目前比较常用的Init系统,但是因为其不够UNIX,也有部分人并不喜欢这样的实现。由红帽与免费桌子两大巨头推动,systemd逐渐吞并或者接管了一些不是init系统应该做的事情,而是把init系统变成了一个统一接管一般操作系统所应该提供的一系列服务的一系列daemon。这就是Systemd!这就是SystemdOS

例如:syste.md

OpenRC,是Gentoo的livecd提供的init系统,由于一些维护上的问题,OpenRC的一些组件也逐渐使用了systemd的组件。使用脚本化的Init系统的优势在于更好的灵活性。如果systemd遇到了兼容性问题,可以考虑使用其他Init系统。

内核

Linux,是一个开源的类Unix操作系统内核。

使用 Linux

所谓的GNU/Linux,究竟是GNU多一点还是Linux多一点?

当然更多的是GNU的生态。

那个男人: man

你可以问这个男人自己这个男人是谁:

man man

man - an interface to the system reference manuals

也可以进入使用浏览器阅读线上的文档man

进入文档后,按h可以调出帮助页面

/可以搜索

q退出

终端: terminal

我们与Linux系统最常见的使用场景是在终端上使用的,需要了解一下Linux的TTY系统。

比较常用的是显示器与键盘,使用ctrl+alt+F<num>来切换。

其次是终端模拟器,例如konsole,这里使用的则是pty(pseudo terminal device),其中ptmx是master端,pts是slave端。

最后你可能需要使用SSH远程连接到其他Linux主机,与上面同理。

从现在开始,你可以随时使用man调出任何概念的文档。例如:man tty man pty

Shell

这里的shell指/bin/sh,通常情况下是指向bash的软链接。

除了bash,还有csh,zsh,powershell等POSIX的shell,需要注意fish并不打算支持POSIX,windows上的powershell由于缺少GNU的支持,所以很多实现并不是真正的命令。

这里的场景是终端中的bash shell。关于如何写脚本,下面进行讨论。

prompt

shell最前面的提示符prompt,这部分由四个环境变量决定:PS1 PS2 PS3 PS4

一般由用户名,hostname,当前工作路径组成,其次还可以加上时间,python/nodejs等虚拟环境的指示器。

这是bash的prompt

oripoin@xanmod ~ $ echo $PS1
\[\033]0;\u@\h:\w\007\]\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\]

而这是zsh的prompt

╭─    ~ ········································· ✔  11:10:50  ─╮
╰─ echo $PS1                                                           ─╯
${$((_p9k_on_expand()))+}%{${_p9k__raw_msg-}${_p9k__raw_msg::=}%}${(e)_p9k_t[7]}${_p9k__1-${${:-${_p9k__d::=0}${_p9k__rprompt::=${_p9k__1r-${${:-${_p9k__bg::=NONE}${_p9k__i::=0}${_p9k__sss::=${(Q)${:-"%\{%\}"}}}}+}${${:-${P9K_CONTENT::=}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=8}}${_p9k__n:=${${(M)${:-x$_p}}${_p9k__e::=${${_p9k__1rstatus+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}1}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{000\}%F{002\}${${(M)_p9k__e:#11}:+ }$_p9k__v${${:-${_p9k__w::=%b%K{000\}%F{002\} %b%K{000\}%F{002\}}${_p9k__sss::=%b%K{000\}%F{002\} }${_p9k__i::=1}${_p9k__bg::=000}}+}}${${:-"${${(%):-%j}:#0}"}:+${${:-${P9K_CONTENT::=""}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=12}}${_p9k__n:=${${(M)${:-x$_p9k__bg}:#x(000|000)}:+14}}$}}${_p9k__e::=${${_p9k__1rbackground_jobs+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}1}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{000\}%F{006\}${${(M)_p9k__e:#11}:+ }$_p9k__v${${:-${_p9k__w::=%b%K{000\}%F{006\} %b%K{000\}%F{006\}}${_p9k__sss::=%b%K{000\}%F{006\} }${_p9k__i::=3}${_p9k__bg::=000}}+}}}${${:-"${${(%):-%#}:#\#}"}:+${${:-${P9K_CONTENT::=%n@%m}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=20}}${_p9k__n:=${${(M)${:-x$_p9k__bg}:#x(00}}${_p9k__e::=${${_p9k__1rcontext+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{000\}%F{003\}${${:-${_p9k__w::=%b%K{000\}%F{003\} %b%K{000\}%F{003\}}${_p9k__sss::=%b%K{000\}%F{003\} }${_p9k__i::=29}${_p9k__bg::=000}}+}}}${${:-"${${(%):-%#}:#\%}"}:+${${:-${P9K_CONTENT::=%n@%m}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=24}}${_p9k__n:=${${(M)${:-x$_p9k__bg}:#x(000|000)}:+26}}${_p9k__n:=27}${_p9k__c::}}${_p9k__e::=${${_p9k__1rcontext+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{000\}%F{001\}${${:-${_p9k__w::=%b%K{000\}%F{001\} %b%K{000\}%F{001\}}${_p9k__sss::=%b%K{000\}%F{001\} }${_p9k__i::=29}${_p9k__bg::=000}}+}}}${${:-"${${:-$_p9k__keymap.$_p9k__zle_state}:#(vicmd.*|vivis.*|vivli.*|*.*insert*)}"}:+${${:-${P9K_CONTENT::=OVERTYPE}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=28}}${_p9k__n:=${${}}${_p9k__e::=${${_p9k__1rvi_mode+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{003\}%F{000\}${${:-${_p9k__w::=%b%K{003\}%F{000\} %b%K{003\}%F{000\}}${_p9k__sss::=%b%K{003\}%F{000\} }${_p9k__i::=36}${_p9k__bg::=003}}+}}}${${:-"${(M)${:-$_p9k__keymap$_p9k__region_active}:#vicmd0}"}:+${${:-${P9K_CONTENT::=NORMAL}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=32}}${_p9k__n:=${${(M)${:-x$_p9k__bg}:#x(002|}}${_p9k__e::=${${_p9k__1rvi_mode+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{002\}%F{000\}${${:-${_p9k__w::=%b%K{002\}%F{000\} %b%K{002\}%F{000\}}${_p9k__sss::=%b%K{002\}%F{000\} }${_p9k__i::=36}${_p9k__bg::=002}}+}}}${${:-"${(M)${:-$_p9k__keymap$_p9k__region_active}:#(vicmd1|vivis?|vivli?)}"}:+${${:-${P9K_CONTENT::=VISUAL}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=36}}${_p9k__n:=${${(M)${:-x$_}}${_p9k__e::=${${_p9k__1rvi_mode+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{004\}%F{000\}${${:-${_p9k__w::=%b%K{004\}%F{000\} %b%K{004\}%F{000\}}${_p9k__sss::=%b%K{004\}%F{000\} }${_p9k__i::=36}${_p9k__bg::=004}}+}}}${${:-${P9K_CONTENT::=11:10:50}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=40}}${_p9k__n:=${${(M)${:-x$_p9k__bg}:#x(007|007)}:+42}}${_p9k__n:=43}${_p9k__v::=}${_p9k__c::="${P9K_CON}}${_p9k__e::=${${_p9k__1rtime+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}1}}}+}${${_p9k__e:#00}:+${_p9k_t[$_p9k__n]/<_p9k__w>/$_p9k__w}${_p9k__c}%b%K{007\}%F{000\}${${(M)_p9k__e:#11}:+ }$_p9k__v${${:-${_p9k__w::=%b%K{007\}%F{000\} %b%K{007\}%F{000\}}${_p9k__sss::=%b%K{007\}%F{000\} }${_p9k__i::=40}${_p9k__bg::=007}}+}}$_p9k__sss%b%k%f}${_p9k__1r_frame-"%244F─╮"}}${_p9k__lprompt::=${_p9k__1l_frame-"%244F╭─"}${_p9k__1l-${${:-${_p9k__bg::=NONE}${_p9k__i::=0}${_p9k__sss::=%f}}+}${${:-${P9K_CONTENT::=}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=44}}${_p9k__n:=${${(M)${:-x007}:#x($_p9k__bg|${_p9k__bg:-0})}:+46}}${_p9k__n:=47}${_p9}}${_p9k__e::=${${_p9k__1los_icon+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}0}}}+}${${_p9k__e:#00}:+${${_p9k_t[$_p9k__n]/<_p9k__ss>/$_p9k__ss}/<_p9k__s>/$_p9k__s}${_p9k__c}%b%K{007\}%F{232\} ${${:-${_p9k__s::=%F{007\}}${_p9k__ss::=}${_p9k__sss::=%F{007\}}${_p9k__i::=1}${_p9k__bg::=007}}+}}${${:-${P9K_CONTENT::="%{d%}${:-"%B%F{255}"}${(Q)${:-"\~"}}${:-"%b%K{004}%F{254}"}%{d%}"}${_p9k__n::=}${${${_p9k__bg:-0}:#NONE}:-${_p9k__n::=48}}${_p9k__n:=${${(M)${:-x004}:#x($_p9k__bg|${_}}${_p9k__e::=${${_p9k__1ldir+00}:-${${(%):-$_p9k__c%1(l.1.0)}[-1]}1}}}+}${${_p9k__e:#00}:+${${_p9k_t[$_p9k__n]/<_p9k__ss>/$_p9k__ss}/<_p9k__s>/$_p9k__s}${_p9k__v}${${(M)_p9k__e:#11}:+ }${_p9k__c}%b%K{004\}%F{254\} ${${:-${_p9k__s::=%F{004\}}${_p9k__ss::=}${_p9k__sss::=%F{004\}}${_p9k__i::=2}${_p9k__bg::=004}}+}}${(e)_p9k__vcs}%b%k$_p9k__sss%b%k%f}}}+}${(e)_p9k_t[6]}${${_p9k__h::=0}+}${${_p9k__d::=$((_p9k__m-_p9k__h))}+}${_p9k__lprompt/\%\{d\%\}*\%\{d\%\}/${_p9k__1ldir-${:-"%B%F{255}"}${(Q)${:-"\~"}}${:-"%b%K{004}%F{254}"}}}${${_p9k__m::=$((_p9k__d+_p9k__h))}+}${${_p9k__g+
}:-${:-"%F{244}"}${${${_p9k__m:#-*}:+${${_p9k__1g+${(pl.$((_p9k__m+1)).. .)}}:-${(pl.$((_p9k__m+1))..·.)}}$_p9k__rprompt${_p9k_t[$((1+!_p9k__ind))]}}:-
}%b%k%f}}${_p9k__2-${_p9k__2l_frame-"%244F╰─"}${_p9k__2l-${${:-${_p9k__bg::=NONE}${_p9k__i::=0}${_p9k__sss::=%f}}+}%b%k$_p9k__sss%b%k%f${:-" %b%k%f"}}}${${COLUMNS::=$_p9k__clm}+}
╭─    ~ ········································· ✔  11:10:53  ─╮
╰─ echo $PS2                                                           ─╯
%B%F{green}%n@%m%k %B%F{blue}%1~ %_> %b%f%k
╭─    ~ ········································· ✔  11:10:56  ─╮
╰─ echo $PS3                                                           ─╯
%B%F{green}%n@%m%k %B%F{blue}%1~ ?# %b%f%k
╭─    ~ ········································· ✔  11:10:58  ─╮
╰─ echo $PS4                                                           ─╯
+%N:%i>

环境变量

现在解释一下上面提及的环境变量,环境变量通常是bash运行时的预设,属于bash中的变量,有如下的加载顺序:

  • 交互式非登录: ~/.bashrc
  • 登陆shell:/etc/profile /etc/profile.d ~/.bash_profile ~/.bash_login ~/.profile ~/.bashrc

设置环境变量有多种方式:set/unset env export source ,使用上是有部分区别的,以设置var=1为例,下面的不同命令将var设置为字符串1

命令使用描述
setset var=1只在当前shell的进程内有效
envenv var=1为将要执行的子进程设置环境变量,这个命令的输出会包含当前所有的环境变量
exportexport var=1将一个shell本地变量提升为当前shell进程的环境变量,可以被子进程自动继承
sourcesource example.bash在当前shell进程环境中运行脚本,通常用来引用其他文件中的环境变量

对于Gentoo中的系统环境变量,Gentoo做了一层更加整洁的wrapper,可以简单地用A=B这样的方式把环境变量加入/etc/env.d/中,env-update将按照顺序加载这些环境变量。在本机中的环境变量,请加入/etc/env.d/99local中,不然在滚动时etc-update可能会要求你修改为软件包分发的环境变量。

readline

sys-libs/readlineapp-shells/bash的一个依赖,是GNU的一部分,他从用户输入中获取一行的字符,交给shell处理。默认是emacs的风格,vi的风格是可选的。

如果你想用C/C++写一个交互式的工具,readline是一个不错的选择。

builtins

现在整理一下bash所提供的功能,这部分又叫做bash的内建命令,包括::, ., [, alias, bg, bind, break, builtin, caller, cd, command, compgen, complete, compopt, continue, declare, dirs, disown, echo, enable, eval, exec, exit, export, false, fc, fg, getopts, hash, help, history, jobs, kill, let, local, logout, mapfile, popd, printf, pushd, pwd, read, readonly, return, set, shift, shopt, source, suspend, test, times, trap, true, type, typeset, ulimit, umask, unalias, unset, wait

其中比较重要的有:alias,cd,echo,exit,export,history,jobs,kill,pwd,ulimit,unset。在下面的表格中,比较重要的已经加粗处理。

builtins说明
: [arguments]空命令
. filename [arguments]读取并执行指定文件中的命令
source filename [arguments]在当前shell进程环境中运行脚本,通常用来引用其他文件中的环境变量
alias [-p] [name[=value] ...]用于创建别名,常见的ll la,都是ls的别名
bg [jobspec ...]将作业以后台模式运行
bind绑定按键
break [n]退出n层循环
builtin shell-builtin [arguments]运行内建命令
caller [expr]返回当前子调用的上下文,示例
cd [-L\|[-P [-e]] [-@]] [dir]更换当前目录
command [-pVv] command [arg ...]运行命令
compgen [option] [word]生成补全
complete显示如何补全
compopt修改指定单词的补全选项
continue [n]继续n次迭代
declare [-aAfFgiIlnrtux] [-p] [name[=value] ...]
typeset [-aAfFgiIlnrtux] [-p] [name[=value] ...]
声明变量
dirs [-clpv] [+n] [-n]显示当前目录
disown [-ar] [-h] [jobspec ... | pid ... ]从进程作业表中刪除指定的作业
echo [-neE] [arg ...]回显
enable [-a] [-dnps] [-f filename] [name ...]启用或禁用指定的内建shell命令
eval [arg ...]将指定的参数拼接成一个命令,然后执行该命令
exec [-cl] [-a name] [command [arguments]]用指定命令替换 shell 进程
exit [n]以n的状态码退出shell
export [-fn] [name[=word]] ...
export -p
设置子 shell 进程可用的变量
fc [-e ename] [-lnr] [first] [last]
fc -s [pat=rep] [cmd]
从历史记录中选择命令列表
fg [jobspec]将作业以前台模式运行
getopts optstring name [arg ...]分析指定的位置参数
hash [-lr] [-p filename] [-dt] [name]查找并记住指定命令的全路径名
history显示命令历史记录
jobs列出活动作业
kill向指定的进程 ID(PID) 发送一个系统信号
let arg [arg ...]计算一个数学表达式中的每个参数
local [option] [name[=value] ... \| - ]在函数中创建一个作用域受限的变量
logout退出shell
mapfile [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]从 STDIN 读取数据行,并将其加入索引数组
readarray [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]从 STDIN 读取数据行并将其放入索引数组
popd [-n] [+n] [-n]从目录栈中删除记录
printf [-v var] format [arguments]格式化输出
pushd [-n] [+n] [-n]
pushd [-n] [dir]
向目录栈顶添加一个目录
pwd [-LP]输出当前的绝对路径
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]从 STDIN 读取一行数据并将其赋给一个变量
readonly [-aAf] [-p] [name[=word] ...]从 STDIN 读取一行数据并将其赋给一个不可修改的变量
return [n]强制函数以某个值退出
set [--abefhkmnptuvxBCEHPT] [-o option-name] [arg ...]
set [+abefhkmnptuvxBCEHPT] [+o option-name] [arg ...]
设置并显示环境变量的值和 shell 属性
shift [n]将位置参数依次向下降一个位置
shopt [-pqsu] [-o] [optname ...]打开/关闭控制 shell 可选行为的变量值
suspend [-f]暂停 Shell 的执行,直到收到一个 SIGCONT 信号
test expr基于指定条件返回退出状态码 0 或 1
times显示累计的用户和系统时间
trap [-lp] [[arg] sigspec ...]如果收到了指定的系统信号,执行指定的命令
type [-aftpP] name [name ...]显示指定的单词如果作为命令将会如何被解释
ulimit [-HS] [-abcdefiklmnpqrstuvxPRT [limit]]为系统用户设置指定的资源的上限
umask [-p] [-S] [mode]为新建的文件和目录设置默认权限
unalias [-a] [name ...]刪除指定的别名
unset [-fv] [-n] [name ...]刪除指定的环境变量或 shell 属性
wait [-fn] [-p varname] [id ...]等待指定的进程完成,并返回退出状态码

Coreutils

coreutils在一定程度上与bash的一些命令重合。有这些工具,你可以完成基本上所有的任务。由于这些命令是最常用的命令,所以在我看来都是重点。(乐)

basename NAME [SUFFIX]

去掉命令前面的路径

cat [OPTION]... [FILE]...

连接(concat)文件的内容并且输出到STDOUT

是的,你可以一下子cat很多文件。

这个命令通常与less或者more一起使用来浏览上下文;与grep一起使用来找到某些关键字。

chgrp [OPTION]... GROUP FILE...

把某一个组中的文件改为另一个组

chmod

更改文件的黏滞位,可以直接使用数字定义,或者使用+或者-来修改w rx属性。

注意:尽可能不要直接使用chmod 777 [file]

修改路径下的所有文件使用-r选项。

chown

更改文件的用户与组

修改路径下的所有文件使用-r选项。

chroot

更改根为指定的路径

这个命令通常用于切换用户空间,或者在其中执行任务,也常用于系统安装与修复系统。

一个常用的warpper为Arch Linux的arch-install-scripts
工具中提供的arch-chroot。在Gentoo Linux中,通常需要先挂载以下的路径。

mount --types proc /proc /mnt/gentoo/proc
mount --rbind /sys /mnt/gentoo/sys
mount --make-rslave /mnt/gentoo/sys
mount --rbind /dev /mnt/gentoo/dev
mount --make-rslave /mnt/gentoo/dev
mount --bind /run /mnt/gentoo/run
mount --make-slave /mnt/gentoo/run

在其他系统中使用,也基本需要遵循以上的挂载条件,另外一些发行版可能需要下面的操作:

test -L /dev/shm && rm /dev/shm && mkdir /dev/shm
mount --types tmpfs --options nosuid,nodev,noexec shm /dev/shm
chmod 1777 /dev/shm /run/shm

cp

复制文件和路径

cut OPTION... [FILE]...

从文件中删除某部分到STDOUT

date

输出或者修改系统时间(软件)

dd

转换或者复制文件

一般用法:dd if=[FILE] of=[FILE]

df

报告文件系统使用情况

使用-h选项将输出格式化为人类能读的形式

dir

列出路径下的内容

类似于Windows

dirname

输出最近一层的路径名称

du

计算文件空间占用

使用-h选项将输出格式化为人类能读的形式

使用--max-depth=指定深度

echo

回显:查看环境变量,使用管道向文件中echo内容

env

在某一个环境中运行程序

expr

计算表达式

false

不做任何事情,以成功的状态退出

head

输出文件的开头

ln [OPTION]... TARGET... DIRECTORY

创建链接,使用-s创建软链接

ls

列出路径内容。这个命令在很多发行版或者rc文件中有alias。

以咱的zshrc为例:

# ls
# -v: natural sort of version
alias ls='ls                                  -v --classify --group-directories-first --color=auto'
alias  l='ls -l              --human-readable -v --classify --group-directories-first --color=auto'
alias ll='ls -l              --human-readable -v --classify --group-directories-first --color=auto'
alias la='ls -l --almost-all --human-readable -v --classify --group-directories-first --color=auto'

mkdir

新建路径,使用-p按需建立父目录。

mkfifo

建立输入输出管道

mknod

创建块或者字符特殊文件

mktemp

创建临时文件或目录

mv

移动或重命名文件

pwd

输出当前绝对路径

readlink

输出链接的目标

rm

移除文件或路径。

注意,请不要使用或者提及这项命令rm -rf /

Linux上默认没有“回收站”这个东西,除非对rm命令进行一层封装,或者使用桌面环境中的文件管理器。一旦误删文件之后,请立即对操作的磁盘进行断电,并且停止写入,然后尝试找到删除的文件。

rmdir

移除空路径

seq

输出一系列的数字

sleep

延迟/等待一段时间

sort

排序

stty

修改命令后设置

sync

如果你发现在Linux上,对文件的写入或读取操作一般很快;如果你发现Linux上,内存总是很快地被占用干净。这都是缓存在工作,Linux的文件缓存让Linux桌面系统在HDD磁盘上具有更快的响应速度。与Windows的prefetch不同,文件缓存是被动的,且默认存在的,他一方面加快了磁盘IO,但另一方面缺有可能造成文件的丢失。

使用sync命令把缓存同步到持久化存储上。

tail

输出文件的最后的内容

一般加入-f选项,持续查看文件的增加。

touch

修改时间戳。如果文件不存在,则新建这个文件。

tr

将字符进行替换压缩和删除

true

不做任何事情,以成功的状态退出

tty

输出当前的tty或者pty

uname

打印系统信息,不确定的话,就全部打印出来吧:uname -a

vdir

详细列出目录下的内容,相当于上面的ll,只不过不大适合人类阅读。

wc

统计文件中的行数、字数或者字节数

yes [STRING]

复读机。

实在想不出这个东西有什么用,她确实在交互式的命令行上有点作用,问题是,真的有什么上游不做非交互式的命令行吗?getopts干什么的呢?

上面这部分属于/bin


下面这部分属于/usr/bin/, 并且不包括全部命令

arch

输出架构

{b2,md5}sum base{32,64} sha{1,224,256,384,512}sum

用于验证,编码于解码

id

输出用户和组,包括名称和ID

install

安装文件,常见于打包。复制,包括用户和用户组及其权限。

nice

调整程序的友好程度/资源优先级

nohup

运行程序,但是输出不定向到tty

tee

STDIN写入STDOUT或者文件。

who whoami

谁在登录?我是谁?这是个问题


除此之外,还有一些系统必备的工具,这些也很常用,一般以系统依赖或者system集合本身出现在依赖树或者系统中

sed

这是一个流编辑器。通常用于脚本中编辑文件,或者在命令行中编辑文件,常用于替换与一些正则表达式的实现。

gawk

Gawk是GNU对awk编程语言的实现,常用来模式扫描与处理。

grep

grep是一个文本查找或搜索工具,同意支持正则,可以处理很多文件。

find

用于在指定目录下查找文件。

Editor: Vim or nano

见过一些痴迷EAMCS的人,emacs lisp很好用,EmacsOS也很好用,但是这些已经超越了一个编辑器应该做的事情。

Gentoo的installcd默认不提供Vim,而且stage3镜像也不提供,默认的editor是nano。但是admincd是提供的,而且你也需要在新安装的系统上安装Vim。

Emacs

因为Emacs Lisp的存在,Emacs可以做到任何事情,这也是EmacsOS的由来。

写代码,与LSP配合;写笔记或者文档,将其发布成网站;管理Git项目;管理窗口,作为窗口管理器或者说桌面

Nano

Gentoo选择Nano作为默认的编辑器,如果你不想学习Vim,另一个不错的选择就是Nano。

nano [file]就可以直接编辑文件,完成编辑后,Ctrl+O保存,Ctrl+X保存并退出。

Vim

Vim的过去:ed,vi
Vim的现在:Vim(Vi IMproved)
Vim的未来:Neovim

Normal mode

默认的模式

  • h:左移
  • j:下移
  • k:上移
  • l:右移
  • u:undo
  • Ctrl+R:redo

如果不知道在什么模式,可以狂按Esc进入此模式。

Insert Mode

在此模式可以插入

  • i:插入,insert,在光标前
  • a:添加,append,在光标后
  • o:新建下一行插入

此外

  • I:插入,insert,在行首
  • A:添加,append,在行末
  • O:新建上一行插入
Visual Mode

v进入此模式。

Command Mode
  • ::输入命令
  • /:查找,有些vim的编译并不会自动跳转
Replace Mode

R进入

删除,复制,剪切和粘贴
  • backspace:一般模式下是回退,插入模式下删除光标前的内容
  • delete:删除,删除光标选中/后的内容
  • d:删除Visual Mode中选中的内容,并加入vim的粘贴板(剪切)
  • dd:删除一行,并加入vim的粘贴板(剪切)
  • y:yank,复制Visual Mode中选中的内容到vim的粘贴板
  • yy:复制一行内容到vim的粘贴板
  • p:粘贴vim粘贴板中的内容
常用命令
  • :q:退出
  • :w:写入
  • :x:保存并退出
  • :[num]:跳转至某一行
  • /foo:搜索foo
  • #:搜索光标后的单词并跳转至下一处

OpenSSH

OpenSSH是一套远程操作工具。

在Linux上一般使用OpenSSL的后端,在Windows上使用LibreSSL这个分支。行为上没有什么差别,但是Windows上可能会遇到权限问题。

ssh

ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-J destination] [-L address] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] destination [command [argument ...]]

一般用法:ssh username@(hostname, ip}

-p指定端口

如果用户名相同,并且远程主机有ip或者在本机的/etc/hosts,dns或本地dns缓存中存有域名与ip的对应,则可以省略用户名,使用直接ssh加域名。

scp

scp source ... target

通过ssh复制文件,常用于没有rsync的情况。

sftp

额,安全的ftp实现,不用。

GPG and SSH keys

一般使用这两个密钥验证身份。虽然SSH的客户端可以由GPG来接管,但是咱没有尝试成功,而且貌似一般也是来分开管理的。由SSH Keys来验证远程连接的身份,由GPG Keys来验证作者的身份,二者并不冲突。二者均需要一个公钥,一些私钥则用于不同的用途。

SSH keys

在Windows和在Linux上的操作基本相同,不需要git bash,使用Windows自带的OpenSSh客户端即可。

使用ssh-keygen生成密钥对

使用ssh-copy-id上传公钥

GPG keys

由于默认使用sign-off会产生很多误会,甚至可以让某些人可以冒充别人,所以使用GPG加密可以在互联网上验证你的身份。

使用gpg --full-generate-key生成公钥

使用gpg --expert --edit-key xxxx编辑公钥并生成子密钥

使用gpg --list-secret-keys --keyid-format=long列出密钥

使用git config user.signingkey xxx告诉git使用gpg keys

使用[ -f ~/.bashrc ] && echo 'export GPG_TTY=$(tty)' >> ~/.bashrc添加环境变量是的GPG可以加密commits

使用git config commit.gpgsign true配置git使用gpg加密

Git

Git是一个分布式的版本管理工具,无论是本地管理项目还是组织上一起协作开发,都是好用的。

常用命令:

  • git init: 初始化目录
  • git add xxx: 添加暂存文件
  • git commit:提交,-S签名,-ssign-off,-m添加提交信息
  • git push <remote name> :推送
  • git clone:克隆,建议使用ssh
  • git fetch <remote>:获取远程
  • git pull:拉去远程,会改动commit
  • git rebase:变基,建议手动fetch,然后手动变基
  • git revert:使用一次commit来回滚到之前的commit
  • git reset:删除前一次commit

rsync

Gentoo默认使用rsync来同步ebuild仓库,但是由于rsync会对上游镜像源造成较大的服务器压力,每日会有使用次数限制。

此外,rsync是一个很好用的跨磁盘,跨主机文件传输/备份工具。有断点续传,压缩加速的特点。

rsync -avuP RESOUCE TARGET

aria2c or wget

很多发行版默认使用wget来获取网络上的文件。一些情况下wget更加通用,但是aria2c支持的功能更加丰富,例如:磁力链接,多线程下载。

aria2c -x 16 -s 16 <link>

Rust 替代品

Rust是一个基于llvm的更加严格与安全的编程语言。标榜着更加现代化,很多项目也正在实现一些更加好用的功能。

ripgrep

使用rg来获得更好性能的grep体验

fd

与文件描述符同名,Debian上这个包名为fd-find

默认忽略了隐藏路径,同样是更好的性能。

bash script

在Gentoo上,所有的开发工具都是齐全的,这意味着你可以直接开发一些小应用而不用担心依赖问题。例如,Python,C/C++,根据使用情况的不同,还有更多更复杂的开发工具会被直接作为系统依赖拉进依赖树。

portage的ebuild脚本,本质上就是bash脚本。

想要让Gentoo Linux支持bash脚本的运行,你需要在把CONFIG_BINFMT_SCRIPT编译进内核,不要设置成M或者N,大多数系统将不会启动成功。

解释器

如上,脚本的第一行#!/path/to/interpreter用于告诉Linux内核解释器的位置:

#!/bin/bash
# do something

Hello, world!

可以在内存中的临时目录里面操作

cd /tmp
echo echo Hello, world! | tee hello.bash

执行

接着,bash hello.bash,输出为Hello, world!

如果不使用解释器,需要给脚本加上可执行权限:chmod +x hello.bash,然后./hello.bash

变量

创建变量:var=1

删除变量:unset var

创建数组:array=(1 2 3)

数组迭代:array[1] array[2] array[3]

这些基本就够了,不会真的有人想不开拿bash算1 + 1 = 2吧。

echo `expr 1 + 1`

流程控制

个人认为以下几种就足够使用了,因为本人真的没用过其他复杂的流程控制。(Python他不香吗?)

if-else
if condition1
then
    command1
elif condition2
then
    command2
else
    commandN
fi
for
for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done
case
case var in
mode1)
    command1
    command2
    ...
    commandN
    ;;
mode2)
    command1
    command2
    ...
    commandN
    ;;
esac

函数

下面是一个危险的例子,如果尝试的话请先保存好需要保存的文件。

:(){ :|:& };:
学名叫做:“线程炸弹”

-)

一般的函数

[ function ] funname [()]

{

    action;

    [return int;]

}

管道与重定向

  • |:管道,每一个进程的 stdout 作为下一个进程的 stdin
  • command > file:输出重定向到 file
  • command < file:输入重定向到 file
  • command >> file:输出以追加的方式重定向到 file

GNU toolchains or crossdev

Gentoo Linux基本带有完善的开发环境,而且本身就是一种交叉编译的环境,并且想要配置其他交叉编译的环境,也是十分简单。

其他系统上,例如Debian,需要使用apt install build-essential来获取打包的基本编译环境;Arch上则需要使用pacman -S base-devel来安装基本的编译环境来使用aur的打包。

如果你使用了git版本的软件或者unstable分支的软件,一些debug工具是需要的:emerge valgrind gdb

此外Gentoo是有llvm的测试分支的,但是很多system集合中的包需要打patch才能emerge成功。桌面用户基本躲不开llvm,并且一些应用使用Clang才能获得更好的性能。但需要注意的是llvm的target已经被mask固定住了,随意更改这些编译目标可能会损坏llvm工具链。

Crossdev

Crossdev是给portage提供交叉编译能力的一个脚本封装,这套环境用于跨架构打包或者简单地编译一些程序。

gcc

gcc的架构支持使用不同的CATEGORY来区分,本机的是sys-devel/gcc,64位mingw的则是cross-x86_64-w64-mingw32/gcc

对于一个Hello, world!

#include <stdio.h>

int main(){
        printf("Hello, world!\n");
}

编译

gcc hello.cpp -o hello #默认debug,不优化
gcc hello.cpp -o hello -g #加入调试信息

执行

chmod +x ./hello
./hello

GNU Autotools

此处只提及,makefile基本上与bash脚本无异

Cmake

autotools的一层封装,建议直接使用cmake。

增加debug选项:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb")

gdb

使用gdb需要为二进制程序在编译时添加debug编译选项。

gdb hello

常用命令:

命令描述
r运行
b设置断点
p查看变量
n下一个,可以添加步数
c运行直到下一个断点

valgrind

用于检测有无内存泄漏

需要glibc在编译时有-fno-builtin-strlen编译选项

valgrind hello
知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
上一篇
下一篇