Ubuntu 安装

安装

下载 ISO 可至 下载 Ubuntu | Ubuntu 正体中文站 ,安装时不要更新,按下列安装:

Continue without updating

  • Install OpenSSH server
    如果要安装就打勾吧

最后会出现 Cancel update and reboot (奇怪!不是已经选了 Continue without updating)。按下 Cancel update and reboot 后时间没有比较快,那就等它吧。

安装系统后,先以 IP 登录主机,建议采用 Windows-Terminal 来连接 linux 主机。安装 Terminal 后采用 ssh 终端机进入系统来配置。

安装 ssh,让其他计算机采用 ssh 登录方便输入
安装 ssh (Install OpenSSH server 没打勾):
sudo apt install ssh -y

Ubuntu 18/20 查看一下 IP:
ip -c a

如位置如下
inet 192.168.1.20/24 brd 172.31.168.254 scope global dynamic ens32

由终端机以 IP 位置登录:
ssh user@192.168.1.20 (1)
1 user 为安装 Ubuntu 时,输入的帐号。
root 的缺省密码是什么?怎么无法登录?

因为 root 未设置密码,必须设置密码才行

可是要怎么设置?
采用 sudo 设置 root 密码
sudo passwd root (1)
1 运行时要注意如果 sudo 需要密码,那么第一次输入的密码是 sudo 的密码 (输入目前登录帐户的密码), 第二、三次的密码才是 root 帐户的密码。
sudo 免密码,运行 sudo 第一次都要输入密码实在麻烦

使用 sudo 要设置 /etc/sudoers,但建议不要直接编辑该文件。

编辑 sudoers 运行下列
sudo visudo (1) (2)
1 如果运行出错改用下列
取得 root「超级用户 (superuser)」权限:
su

以 root 帐户运行:
visudo
2 visudo 会采用常用的编辑器 (如 nano),离开编辑器时;若内容有错误,它会提示:
>>> /etc/sudoers: syntax error near line 26 <<<
What now?
Options are:
  (e)dit sudoers file again
  e(x)it without saving changes to sudoers file
  (Q)uit and save changes to sudoers file (DANGER!)
在文件后面加入免密码的帐户 (个别帐户设置)
user ALL=NOPASSWD: ALL(1)
1 本例的帐户为 user
或者修改 sudo 群组为免密码
修改
# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

变成
# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) NOPASSWD:ALL

当帐户没有 sudo 权限时错误消息为:
<username> is not in the sudoers file. This incident will be reported.

帐户必须在 sudoers 文件设置的权限内才能运行 sudo 指令。
  • 个别帐户设置

  • sudo 群组设置

上述无 sudo 权限的消息,并非表示「帐户」一定要以个别帐户加入 sudoers 之中,将「帐户」加入至 sudo 群组也能运行 sudo 指令。

列出 sudo 的成员:
grep sudo /etc/group

sudo:x:27:user (1)
1 在安装 Ubuntu 时输入 (新) 的帐户会缺省为 sudo 群组的成员。
sudo 群组的相关指令
将帐户 ubuntu 加入至 sudo 群组:
sudo gpasswd -a ubuntu sudo

将帐户 ubuntu 移出 sudo 群组:
sudo gpasswd -d ubuntu sudo

帐户改变 sudo 群组,需要重新登录才会生效。


sudoers 文件中有一条规则
root ALL=(ALL:ALL) ALL

表示 root 帐户能运行 sudo 也能切换至任何帐户或群组。

  • root ALL=(ALL:ALL) ALL 第 1 个字段,指明帐户 (或群组)。

  • root ALL=(ALL:ALL) ALL 第 1 个 ALL,规范「任何主机」能运行。

  • root ALL=(ALL:ALL) ALL 第 2 个 ALL,帐户可以切换至哪个 (which) 帐户,ALL 表示「所有帐户」。

  • root ALL=(ALL:ALL) ALL 第 3 个 ALL,帐户可以切换至哪个 (which) 群组,ALL 表示「所有群组」。

  • root ALL=(ALL:ALL) ALL 第 4 个 ALL,帐户可运行哪些命令,ALL 表示「所有命令」,NOPASSWD:ALL 表示运行任何命令都不需要密码。

语法为:
用户 可由哪个主机运行=(可成为哪个帐户:可成为哪个群组) [NOPASSWD:] 可运行哪些命令
sudo 可切换帐户或群组来运行命令
sudo --help
 -u, --user=user    以指定的帐户或 ID 运行命令(或编辑文件)
 -g, --group=group  以指定的群组或 ID 运行命令

sudo 在没有指定参数时,是切换至 root 的帐户来运行,用户只要有 sudo 的权限即可运行命令。

ubuntu ALL= ALL

ubuntu 运行 sudo 只能以 root 身份运行命令,sudo 以其他身份运行,则 (一定) 会询问密码,在运行时会出现下列错误:

Sorry, user ubuntu is not allowed to execute
ubuntu ALL=(ALL) ALL

ubuntu 能以 user 帐户身份 (sudo -u user) 来运行,运行群组的身份也是 user。由于没有「成为哪个群组」的权限,运行 sudo -g user 将会出错。

ubuntu ALL=(ALL:ALL) ALL

ubuntu 可以用任何身份来运行命令。

以 ubuntu 来测试 sudo 的权限时,除了 ubuntu 没有在 sudo 的群组之外,也要在注意在虚拟机 /etc/sudoers.d 目录中的文件 (如 90-cloud-init-users) 会缺省 ubuntu 帐户的 sudo 权限。
ubuntu ALL=(ALL) NOPASSWD:ALL
刚安装可采用 dist-upgrade 更新
sudo apt update && sudo apt dist-upgrade -y

运行后下列应该无列表:
sudo apt list --upgradable
检查时区是否正确
显示日期的 RFC 格式:
date -R

Mon, 21 Sep 2020 06:33:38 +0000

设置时区:
sudo timedatectl set-timezone Asia/Taipei

如果运行错误,采用下列:
sudo dpkg-reconfigure tzdata

选择 Asia - Taipei。

如果没有该命令安装 tzdata
sudo apt install tzdata -y

显示日期的 RFC 格式:
date -R

Mon, 21 Sep 2020 14:35:32 +0800 (1)
1 +0800 则正确。
配置 .bashrc
先看一下要改什么
echo $LANG

C.UTF-8 或 en_US.UTF-8

echo $TIME_STYLE

空值
修改 ~/.bashrc 文件
force_color_prompt=yes (1)

export TIME_STYLE=long-iso (2)
export LANG='en_US.UTF-8' (3)
1 调整 root 终端机提示字符颜色,找出 #force_color_prompt=yes 将注解(#)取消,跟顺序有关位置要正确。
其他帐户也被注解掉了不过却有提示色。
2 加入本行,设置 ls 显示文件的时间格式。
3 默认值如果是 C.UTF-8 (或 en_US.UTF-8) 则不需加入,如 echo $LANG 为空值,则需加入。
套用 ~/.bashrc
source ~/.bashrc

echo $TIME_STYLE
echo $LANG
不提示主要版本更新 (LXC 请忽略本步骤)
sudo nano /etc/update-manager/release-upgrades
/etc/update-manager/release-upgrades 的 Prompt 设为 never
# Prompt=lts
Prompt=never
修改 syslog 日期格式
sudo nano /etc/rsyslog.conf
注消原始格式
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat (1)
1 前面加上 # 即可。
加入下列格式
# 注消原始格式
# $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
# 加入下列格式
$template CustomFormat,"%$NOW% %TIMESTAMP:8:15% %hostname% %syslogtag% %msg%\n"
$ActionFileDefaultTemplate CustomFormat
Ubuntu 16 rsyslog 有 bug 实际的记录有下列的错误
rsyslogd-3003: invalid or yet-unknown config file command 'KLogPermitNonKernelFacility' - have you forgotten to load a module? ...

KLogPermitNonKernelFacility 是 bug,参阅: command KLogPermitNonKernelFacility is currently not permitted

修正 /etc/rsyslog.conf
# Ubuntu 16 将下列注消
$KLogPermitNonKernelFacility
rsyslog 另一个 bug 是 xconsole 并未在系统之中。
rsyslogd-2039: Could not open output pipe '/dev/xconsole':: No such file or directory ...
修正 Ubuntu 16 xconsole
sudo mknod -m 640 /dev/xconsole c 1 3
sudo chown syslog:adm /dev/xconsole
确定一下修改日期格式的记录情况。
sudo tail /var/log/syslog
sudo service rsyslog restart
sudo tail /var/log/syslog
VMWare 采用自动安装修正

更新出错 The repository 'cdrom://Ubuntu-Server …​ does not have a Release file。

sudo nano /etc/apt/sources.list
deb cdrom 开头的设置注解掉或删除 ( Ctrl+K )。
deb cdrom:[Ubuntu-Server ...
再来呢?

配置 samba 方便 Windows 能以 Linux hostname 登录, 安装 wins 让 Linux 能 ping Windows hostname

拷贝(Clone) ubuntu 虚拟机 MAC 地址相同

Netplan 可能会发生为两台不同机器上的网桥产生相同的 MAC 地址,若新机器以 DHCP 取得则会是相同的 IP。

重建 /etc/machine-id
sudo rm /etc/machine-id
sudo systemd-machine-id-setup
显示如下消息
Initializing machine ID from random generator.
sudo reboot now

帐户及文件权限

帐户

添加用户
无参数会创建用户的家 (home) 目录,home 目录用于保存该帐户的信息,如 登录的参数(.bashrc)、公开密钥 (.ssh):
sudo adduser ubuntu
不创建 home 目录,如该用户不会登录系统,如 www-data 用户或者 samba 帐户,则可不创建:
sudo adduser user1 --no-create-home
改变密码
改变帐户本身的的密码
passwd
改变 root 的密码
sudo passwd root
删除帐户
无参数,仅删除帐号并保留所有文件。
sudo userdel ubuntu (1)
使用 -r 选项,用户 home 目录及系统内的相关的文件一并移除。
sudo userdel -r ubuntu
查看 Linux 帐户
查看所有用户
cat /etc/passwd
列出 www-data 帐户,在安装系统后已经存在。
grep www-data /etc/passwd
列出帐户名
cut -d: -f1 /etc/passwd
其他
whoami 查看自己的用户名
whoami
查看单个用户信息,可得 id 及该帐户属于那些群组
id root
查看登录成功的用户记录
last
查看登录不成功的用户记录
sudo lastb
ubuntu 16 sudo 可能出现 /etc/sudoers.d is world writable 是权限不正确对造成的
正确应如下列
$ls -l /etc/sudoers  /etc/sudoers.d /etc/sudoers.d/README -ld
-r--r----- 1 root root  807 2020-11-21 16:37 /etc/sudoers
drwxr-xr-x 2 root root 4096 2023-01-30 13:20 /etc/sudoers.d
-r--r----- 1 root root  958 2019-10-09 13:55 /etc/sudoers.d/README
修正错误
sudo chmod 440 /etc/sudoers
sudo chmod 775 /etc/sudoers.d
sudo chmod 440 /etc/sudoers.d/README

群组

用户 user 加入群组 group
gpasswd -a user group
用户 user 移出群组 group
gpasswd -d user group
查看 ubuntu 用户群组
grep ubuntu /etc/group (1)
1 /etc/group 内容格式为 group_name:passwd:GID:user_list,第一字段:群组名称,第二字段:群组密码,第三字段:GID,第四字段:用户列表,每个用户之间用 , 逗号分割; 本字段为空时表示为用户本身的群组。

文件权限

chown 改变文件拥有者 (ownership)

chown [-R] 帐号名称[:群组名称] 文件或目录
-R : 进行递归 (recursive) 即次目录下的所有文件都变更。

chown -R www-data:www-data /usr/share/phpmyadmin/tmp
chmod 改变文件权限 (mode)

chmod xyz 文件或目录 [-R]
xyz 可为「数字类型」或「符号类型」。
-R : 进行递归 (recursive) 即次目录下的所有文件都变更。

Linux 文件的基本权限就有九个分别是 owner/group/others,三种身份各有自己的 read/write/execute 权限, 文件的权限字符为 rwxrwxrwx 这九个权限是三组 (三个一组)! 其中,使用数字来代表各个权限,权限数字对照为 r:4 w:2 x:1

755(rwxr-xr-x)

拥有者具备全部权限,其他人只有读取和运行的权限。

754 (rwxr-xr--)

拥有者具备全部权限,群组只有读取和运行的权限,其他人只有读取权限、无运行权、不能读取目录。

644 (rw-r--r--)

文件拥有者具备读取和写入权限,其他人为唯读。 权限中 [r--] 虽然有 r ,但是由于没有 x 权限,因此其他用户并不能进入此目录!

那拥有者能不能进入此目录?

能进?! 那 Linux 有 ghost (拥有者只有 6,不能进)。

这个目录不能用了能删吗?

不能删?! 有 ghost (拥有者有 6,能删)。

但!为什么要删?

您是拥有者改成 744 就好。

X@Y
X @ Y

u)ser 拥有者权限
g)roup 群组权限
o)ther 其它帐号权限
a)ll 全部 (即为 ugo)

+ 加入
- 移除
= 指定

r)ead (读取)
w)rite (写入)
e)xecute (运行)

设置用户家目录,群组及其他无写入权。
chmod go-w ~/

服务及调度

systemctl

开机启动
sudo systemctl enable cron
开机不启动
sudo systemctl disable cron
启动服务
sudo systemctl start cron
停止服务
sudo systemctl stop cron
重启服务
sudo systemctl restart cron
显示服务状态
systemctl status cron
检查 (开机) 是否自动启动服务:
显示服务状态:
systemctl status cron

自动启动:
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2022-11-30 07:19:42 CST; 2 months 1 days ago

不自动启动:
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; disabled; vendor preset: enabled)

查找所有启动的服务再过滤:
systemctl list-unit-files --state=enabled | grep cron

cron.service                           enabled

关机脚本 Shutdown script

创建 myshutdown.sh (习惯把系统服务类放置于 root)
sudo -i
bash -c 'cat > /root/myshutdown.sh' << "EOF"
#!/bin/bash
umount -a -t cifs,nfs -l
EOF

chmod +x /root/myshutdown.sh
exit
创建关机服务
sudo bash -c 'cat > /etc/systemd/system/myshutdown.service' << "EOF"
[Unit]
Description=Shutdown script
DefaultDependencies=no
Before=shutdown.target reboot.target

[Service]
Type=oneshot
ExecStart=/root/myshutdown.sh

[Install]
WantedBy=reboot.target shutdown.target
EOF
激活及禁用
重新加载服务的配置文档:
sudo systemctl daemon-reload

激活 myshutdown:
sudo systemctl enable myshutdown

激活消息:
Created symlink /etc/systemd/system/reboot.target.wants/myshutdown.service → /etc/systemd/system/myshutdown.service.
Created symlink /etc/systemd/system/shutdown.target.wants/myshutdown.service → /etc/systemd/system/myshutdown.service

禁用 myshutdown:
sudo systemctl disable myshutdown

禁用消息:
Removed /etc/systemd/system/shutdown.target.wants/myshutdown.service.
Removed /etc/systemd/system/reboot.target.wants/myshutdown.service.

Service

运行 service 命令显示说明:
service

Usage: service < option > | --status-all | [ service_name [ command | --full-restart ] ]

列出所有安装的服务:
service --status-all

[ - ]  mysql (1)
[ ? ]  mysqld_multi
[ + ]  networking

列出开机自动启动的服务:
service --status-all | grep +

列出服务的命令:
service cron

* Usage: /etc/init.d/cron {start|stop|status|restart|reload|force-reload} (2)
1 +: 服务正在运行。
-: 服务已停止。
?: 服务状态未知。
2 每个服务的命令并不相同,不过一般都会有 start stop status。

service --status-all 为什么会出现问号

其原因是 服务 回传字符串 usage:,可参考 /usr/sbin/service 的内容, 这表示服务脚本并没有实作 status 命令而回传该服务的命令说明。

0	program is running or service is OK
1	program is dead and /var/run pid file exists
2	program is dead and /var/lock lock file exists
3	program is not running
4	program or service status is unknown

如果按上面,服务脚本回传 4,service 是显示 [ - ] mysqld_multi, 那如何让它显示 [ ? ] mysqld_multi 只能回传字符串 usage:

crontab

每项工作的格式有六个字段

分 时 日 月 周 运行的命令

数字范围 分(0 ~ 59) 时(0 ~ 23) 日(1 ~ ?) 月(1 ~ 12) 周(0星期天 ~ 6星期六)

前 5 个字段为时间字段,除了可输入数字外,可采用下列特殊的字符

  • * (星号): 表示任何时间。

  • , (逗号): 多个时段,如时程为 3:00 与 6:00 则为 0 3,6 * * * command

  • - (减号): 范围,如 08:00 至 12:00 间的每小时的 20 分都进行一项工作则为 20 8-12 * * * command

  • /间隔时间: 如每五分钟进行一次则为 */5 * * * * command

上述语法具弹性,如 */5 表示任何时间 (*) 每间隔 (/) 5,依据时间位置可能为每五分钟,每五小时,每五天…​。
8-12/2 表示 8 至 12 每间隔 2 跟 8,10,12 相同。

创建测试档
sudo -i
bash -c 'cat > /root/testCrontab.sh' << "EOF"
#!/bin/bash
date +"%F %T" > /root/testCrontab.txt
EOF

chmod +x /root/testCrontab.sh
exit
测试运行档
sudo /root/testCrontab.sh
查看内容是是否更新
sudo cat /root/testCrontab.txt
crontab 任务计划依据不同帐户有不同的任务计划,可采用 root 简化设置
修改任务计划,使用 crontab -e 可进入常用的编辑器
sudo crontab -e
输入 (当然是粘贴) 下列内容,每一分钟运行 /root/testCrontab.sh
*/1 * * * * /root/testCrontab.sh
crontab 其它相关
将用户的 crontab 全部清除
crontab -r
检查 cron 服务状态
systemctl status cron
service cron status
crontab 文件
sudo -i
cat /var/spool/cron/crontabs/root  (1) (2)

crontab -l (1)
exit
1 可以发现这两者的内容类似。
2 root 任务计划档为 /var/spool/cron/crontabs/root,
如果有其他用户调度,可以查看 /var/spool/cron/crontabs。

套件维护

更新
更新套件
sudo apt update && sudo apt upgrade -y

如果提示 The following packages were automatically installed and are no longer required 则 「移除无作用的套件」,或者不需要提示看直接移除。

移除无作用的套件
sudo apt autoremove --purge -y (1)
1 若出现 not empty so not removed
dpkg: warning: while removing linux-modules-4.15.0-112-generic, directory '/lib/modules/4.15.0-112-generic' not empty so not removed

并不需要去处理,因为 dpkg 不会删除其他套件的文件,当目录不为「空」时,并不会移除目录。
注:不过有时在出现警告后;在运行完成时该目录已不存在。

dist-upgrade

如果一直提示 packages can be updated,表示系统将 Package 升级时有相依性的问题,而此相依性需要安装其它新的 Package 或 影响到其它 Package 的相依性,此 Package 就不会被升级会保留下来,发生这样的现像时,可运行下列得知那些可升级但未被更新的套件。

查看可更新的套件:
sudo apt list --upgradable

或者仿真更新:
apt-get -s upgrade

平时用 apt upgrade 更新,运行 dist-upgrade 选项建议先备份,若为虚拟机那么省事些 snapshot 即可。

运行 dist-upgrade:
sudo apt dist-upgrade -y

运行后下列应该无列表
sudo apt list --upgradable
command not found
运行命令:
ifconfig

出现错误:
-bash: ifconfig: command not found

安装命令:
sudo apt install ifconfig

出现错误:
E: Unable to locate package ifconfig (1)

用 apt-cache search ifconfig 看看是那一个套件:
apt-cache search ifconfig

iproute2 - networking and traffic control tools
net-tools - NET-3 networking toolkit
gnome-nettool - network information tool for GNOME
inetutils-tools - base networking utilities (experimental package)
...

有不少,不知道要装那一个。好吧!网页查到都是装 net-tools。
sudo apt install net-tools -y
1 ifconfig 并非是套件。
查找已安装套件
sudo dpkg -l php*
sudo dpkg -l | grep php

apt list --installed | grep php
apt list --installed | grep net-tools
查找版本 含可安装及版本
apt-cache showpkg <pkgname>
查找可安装的 PHP
apt-cache search --names-only ^php[0-9]+[.]*[0-9]$
运行 apt-get 出错如下:
E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
解决方式
sudo rm /var/lib/dpkg/lock-frontend
sudo rm /var/lib/dpkg/lock
sudo rm /var/cache/apt/archives/lock
dpkg 参数 -l 问题
列出安装的 php 套件:
sudo dpkg -l php*

dpkg-query: no packages found matching phpMyAdmin-4.9.5-all-languages.tar.gz (1)

列出目录中的文件:
ls

phpMyAdmin-4.9.5-all-languages.tar.gz
1 疑? dpkg 是去找目录下的文件! 选项 -l (简要列出套件),怎么跟文件有关? 不知道!
其他
安装套件:
sudo apt install xinetd net-tools -y

 安装指定的版本:
sudo apt install pkgname=version -y

移除套件:
sudo apt autoremove <pkgname> -y --purge

套件已经被卸载,但配置文档仍在
列出已安装套件的指令是 dpkg -l,检查行首是否有 rc 标示,就能判别该套件是已经被移除但还有配置文档残留的项目。
dpkg -l | grep ^rc

rc  libapache2-mod-php7.2

移除 rc:
apt autoremove libapache2-mod-php7.2

怎么没有作用,因为没有安装

删除所有 rc 标记的 dpkg 套件:
dpkg -l | grep ^rc | cut -d' ' -f3 | sudo xargs dpkg --purge

git clone

列出远程标签 (tag)
以 github OpenCC 为例:
git ls-remote --tags https://github.com/BYVoid/OpenCC (1)

...
2ddaffd31f6f9cae776ec2faa4b88d5c45e0d4d6        refs/tags/ver.1.1.4
59cdfe0ac7db87bc3618ccd8943335420fa9ae9b        refs/tags/ver.1.1.5
c3caa5f0221aeaf6ace45b37a608a236272a796c        refs/tags/ver.1.1.6
1 正规要附加 .githttps://github.com/BYVoid/OpenCC.git
下载指定的分支
语法:
git clone [<options>] [--] <repo> [<dir>]

<options> 选项
<repo>    仓库位置
<dir>     指定拷贝目录名称,不指定时为项目名称。

拷贝标签 ver.1.1.5 至目录 1.1.5:
git clone --branch ver.1.1.5 --depth 1 https://github.com/BYVoid/OpenCC 1.1.5 (1)
1 --depth 1 只需拷贝最近的版本。
得知下载分身 (clone) 的标签
切换至分身目录:
cd 1.1.5

以 git log 得知标签:
git log

commit 59cdfe0ac7db87bc3618ccd8943335420fa9ae9b (grafted, HEAD, tag: ver.1.1.5)

以 git tag 得知标签:
git tag

ver.1.1.5

git branch 无法取得 (因为 --depth 1 的原因):
git branch

* (no branch)

gem (Ruby)

一般安装 (apt install)

安装 Ruby:
sudo apt install ruby

显示 Ruby 的版本:
ruby --version

ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]

显示 gem 的版本:
gem --version

2.7.6

gem 安装路径

显示 gem 环境,运行 gem env 如下(省略跟安装路径无关的消息):
RubyGems Environment:
  - INSTALLATION DIRECTORY: /var/lib/gems/2.5.0
  - USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.5.0
  - GEM PATHS:
     - /var/lib/gems/2.5.0
     - /home/ubuntu/.gem/ruby/2.5.0
  - SHELL PATH:
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
套件会安装至两个目录
  • 一个是安装目录 INSTALLATION DIRECTORY: /var/lib/gems/2.5.0
    注:实际上还再附加 gems,如 /var/lib/gems/2.5.0/gems

  • 另一个是用户安装目录 USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.5.0
    注:跟上述的注解一样,要附加 gems。

sudo gem install 会安装至「安装目录」,也会在 /usr/local/bin 创建指令档,由于 gems 是安装用户主目录外,在安装 gems 时需要以 sudo 运行。


卸载 Ruby 前,先卸载 gems,因为要删除指令档。

gems 卸载:
gem uninstall -aIx

-a Uninstall all matching versions
-I Ignore dependency requirements while uninstalling
-x Uninstall applicable executables without confirmation
在运行 uninstall -aIx 时可能会有下列消息
ERROR:  While executing gem ... (Gem::InstallError)
    minitest is not installed in GEM_HOME, try:
        gem uninstall -i /snap/ruby/284/lib/ruby/gems/2.7.0 minitest
按消息提示运行
sudo gem uninstall -i /snap/ruby/284/lib/ruby/gems/2.7.0 minitest (1)
1 如果运行出现下列消息可忽略,/snap/ruby 的目录会在卸载 Ruby (sudo snap remove ruby) 时移除。
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /snap/ruby/284/lib/ruby/gems/2.7.0 directory.
在卸载 Ruby 前先得知安装目录
gem env

apt 安装的结果:
INSTALLATION DIRECTORY: /var/lib/gems/2.7.0
USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.7.0

Snap 安装的结果:
INSTALLATION DIRECTORY: /home/ubuntu/.gem
USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.7.0
卸载 Ruby
apt 卸载 ruby:
sudo apt autoremove ruby -y --purge

Snap 卸载 ruby:
sudo snap remove ruby
删除 Ruby 残留目录
sudo rm -rf /var/lib/gems
sudo rm -rf /home/*/.gem

安装 Snap Ruby.

先更新 Ubuntu:
sudo apt-get update && sudo apt-get upgrade -y

再安装 Snap:
sudo apt install snapd -y

列出 ruby channels:
snap info ruby

3.0/stable:       3.0.5  2022-12-01 (287) 28MB classic
2.7/stable:       2.7.7  2022-12-01 (284) 13MB classic

安装 Ruby 2.7:
sudo snap install ruby --channel=2.7/stable --classic

重置 bash 记忆程序的路径:
hash -r

检查 Ruby 版本:
ruby -v

ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5) [x86_64-linux]

若要安装 (刷新) 3.0:
sudo snap refresh ruby --channel=3.0/stable
显示 gem 环境,运行 gem env 如下(省略跟安装路径无关的消息):
RubyGems Environment:
  - INSTALLATION DIRECTORY: /home/ubuntu/.gem
  - USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.7.0
  - GEM PATHS:
     - /home/ubuntu/.gem
     - /snap/ruby/284/lib/ruby/gems/2.7.0
  - SHELL PATH:
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
     - /usr/bin
套件会安装至两个目录
  • 一个是安装目录 INSTALLATION DIRECTORY: /home/ubuntu/.gem
    注:实际上还再附加 gems,如 /home/ubuntu/.gem/gems

  • 另一个是用户安装目录 USER INSTALLATION DIRECTORY: /home/ubuntu/.gem/ruby/2.7.0
    注:跟上述的注解一样,要附加 gems。

gem install 会安装至「安装目录」,也会在 ~/.gem/bin 创建指令档,但该路径并未在 PATH 中。
安装的 gems 是在用户主目录内,安装时不需要sudo 运行。

~/.gem/bin 加入 PATH,修改 /etc/environment
修改 /etc/environment:
sudoedit /etc/environment
或
sudo nano /etc/environment

套用 /etc/environment:
. /etc/environment
或
source /etc/environment

gem 常用命令

找出可安装的套件及版本:
gem search <套件REGEXP> [选项]

「套件REGEXP」表示找出前置合乎「套件名称」的所有套件,除非加入 -e 选项 (全吻合)。
注:套件名称不可含版号。

search 有那些可用选项:
gem search -h

-a, --all    显示 gem 所有版本
-e, --exact  套件名称全吻合
--prerelease 显示预先发行版本 (注:可简化成 --pre)
列出已安装的套件:
gem list
显示已安装的套件的详细数据:
gem list <套件REGEXP> -d

如详细数据中显示
Installed at: /var/lib/gems/2.5.0

实际安装的路径是在 /var/lib/gems/2.5.0/gems/套件含版号,如果有更新,会显示多个版本。
找出套件指令档路径:
gem which <套件>

一般情况,套件的指令档会在套件的安装路径之中,套件的「数据」可能在指令档的上层。多个版本时应采用 which 来得知目前是用那一个版本。
安装 gem-path,找出套件路径:
安装 gem-path 套件:
gem install gem-path

运行 gem-path 得知套件安装路径:
gem path <套件>

系统信息

Linux 版本

得知版本:
lsb_release -a

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.6 LTS
Release:        16.04
Codename:       xenial

得知版本:
cat /etc/os-release
在 LXC 内是取得 Host 的信息
得知 Fedora Debian 还是 Ubuntu:
cat /proc/version

检查 kernel 版本:
uname -r

4.4.0-179-generic

Linux 内存

free -m
要将单位转换成 Bytes, MB 及 GB, 分别是加上 -b, -m 及 -g,缺省为 Bytes,-v 显示版本。

      total used free shared buff/cache available
Mem:   1478  299  152     20       1025       959
Swap:   979    0  979

total: 安装内存容量
used: 已使用忆体容量
free: 未使用内存,注意!这里不是可用内存
shared: 共享内存(主要)由 tmpfs 使用
available: 可用内存

Linux 行程

top

top - 08:15:01 up 44 min,  1 user,  load average: 0.03, 0.11, 0.10 (1)
Tasks:  63 total,   1 running,  62 sleeping,   0 stopped,   0 zombie (2)
%Cpu(s):  1.5 us,  0.4 sy,  0.0 ni,100.0 id,  0.3 wa,  0.0 hi,  0.1 si,  0.0 st (3)
KiB Mem :  1741400 total,  1600560 free,    73184 used,    67656 buff/cache (4)
KiB Swap:        0 total,        0 free,        0 used.  1557120 avail Mem (5)

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND (6)
    1 root      20   0   56816   6548   5264 S  0.0  0.4   0:00.95 systemd
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.00 kthreadd
    3 root      20   0       0      0      0 S  0.0  0.0   0:00.02 ksoftirqd/0
1 top - 08:15:01 up 44 min, 1 user
08:15:01:目前时间。up 44 min:主机开机时间。1 user:目前登录系统用户数。
load average: 0.03, 0.11, 0.10
系统每 1 分钟、5 分钟、15 分钟的负载情况,load average 数据是每隔 5 秒钟检查一次行程, 按特定算法计算出数值。当数字除以逻辑 CPU 数,结果高于 5 则表示系统已超负荷运转。
2 Tasks: 63 total, 1 running, 62 sleeping, 0 stopped, 0 zombie
目前系统共 63 个行程,1 个正在运行 (running),62 个休眠 (sleeping),0 个已停止 (stopped),0 个僵尸状态 (zombie)。
3 %Cpu(s): 1.5 us, 0.4 sy, 0.0 ni,100.0 id, 0.3 wa, 0.1 hi, 0.1 si, 0.0 st
1.5 us:用户占用 CPU 百分比。
0.4 sy:内核占用 CPU 百分比。
0.0 ni:改变过优先级的行程占用 CPU 百分比。
0.3 wa:IO 等待占用 CPU 百分比。
0.1 hi:硬件中断(Hardware IRQ)占用 CPU 百分比。
0.0 si:软件中断(Software Interrupts)占用 CPU 百分比。
4 KiB Mem: 1741400 total, 1600560 free, 73184 used, 67656 buff/cach
内存使用状态:
1741400 total:物理内存容量
1600560 free:剩余内存容量
73184 used:已使用的内存容量
67656 buff/cach:暂存内存容量
5 KiB Swap: 0 total, 0 free, 0 used. 1557120 avail Mem
swap 使用状态:
0 total:swap 总容量
0 free:已使用的 swap 容量
0 used:剩余 swap 容量
1557120 avail Mem 暂存内存容量
6 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
行程现况: PID:行程 id(Process ID)
USER:该行程用户
PR:行程优先级
NI:nice值 (值越小优先权优高)
VIRT:该行程使用的虚拟内存总量,单位 kb(VIRT=SWAP+RES)
RES:该行程程使用的、未被使用的物理内存大小,单位 kb(RES=CODE+DATA)
SHR:共享内存大小 (单位kb)
S:行程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
%CPU:上次更新到现在的CPU时间占用百分比
%MEM:行程使用的物理内存百分比
TIME+:行程使用的CPU时间总计,单位 1/100 秒
COMMAND:行程名称
top 常用参数

b: Batch mode,更新时产生整个画面,以便用于记录。
d: 指定更新时间(单位:秒)。
o: 指定要输出的字段名称。
p: 指定要观察的 pid。
u: 指定要观察的用户名。

使用 batch mode,观察 pid 6164 的行程并每 2 秒更新一次
top -b -d 2 -p 6164 +

其中 -b 参数是 batch 模式的意思,而 -o 参数则是以 %MEM (内存用量) 排序,

top -b -o %MEM | head -n 17

head -n 17 则是筛选输出前 17 行。

观察用户 www-data 所运行的行程并每 2 秒更新一次
top -d 2 -u www-data

top 显示成 MB

e
Change the scaling factor on the summary display

Shift+e
Change the scaling factor on the task

Shift+w
Save current settings

ps kill

查找 ps 的命令说明,若运行 ps -help 得到的说明并无作用,只在 man ps 有完整说明。

a         显示所有行程 (缺省是当前用户的行程)
u         显示行程的用户
x         显示未附加到终端的行程
-e, -A    显示所有行程
-l        长格式,显示完整的字段。注:不能跟 u 合并使用。
ps 示例
ps aux | grep php
ps -e -l | grep php
kill 删除行程,若要强制结束可使用 -9 参数
kill PID -9
killall 行程名称,将同名称的行程一次删除。
killall 行程名称

Ubuntu 笔记

journalctl

测试 journalctl 时间格式
journalctl --help
-o --output=STRING Change journal output mode (short, short-precise,
                     short-iso, short-iso-precise, short-full,
                     short-monotonic, short-unix, verbose, export,
                     json, json-pretty, json-sse, cat)

sudo journalctl -n 1 -o short
Jan 30 21:56:12

sudo journalctl -n 1 -o short-precise
Jan 30 21:56:31.128574

sudo journalctl -n 1 -o short-iso-precise
2023-01-30T21:57:16.638238+0800

sudo journalctl -n 1 -o short-iso
2023-01-30T21:56:46+0800

sudo journalctl -n 1 -o short-iso-precise
2023-01-30T21:57:16.651012+0800

sudo journalctl -n 1 -o short-full
Mon 2023-01-30 21:57:55

sudo journalctl -n 1 -o short-monotonic
[370817.508650]

sudo journalctl -n 1 -o short-unix
1675087118.807346

Ubuntu 18.04 升级至 20.04

步骤如下:

  1. 备份或虚拟机快照

  2. 更新 Ubuntu 18.04 LTS 所有已安装的套件

    sudo apt update && sudo apt upgrade -y
    sudo reboot
  3. 删除所有未使用的旧套件

    sudo apt autoremove --purge -y
  4. 安装 update-manager-core

    sudo apt install update-manager-core -y
  5. 将 Ubuntu 18.04 LTS 升级到 20.04 LTS

    sudo do-release-upgrade -q
    do-release-upgrad 说明:
    do-release-upgrade --help
    
    -d, --devel-release  升级至开发版本
    -q, --quiet
    ...
    Some third party entries in your sources.list were disabled. You can
    re-enable them after the upgrade with the 'software-properties' tool
    or your package manager.
    
    To continue please press [ENTER] (按下 Enter)
    
    ...
    Installing the upgrade can take several hours. Once the download has
    finished, the process cannot be canceled.
    
     Continue [yN]  Details [d] (输入 y)
    
    ...
    Restart services during package upgrades without asking?
    <Yes> (选取 <Yes>)
    
    Configuration file '/etc/rsyslog.conf'
     ==> Modified (by you or by a script) since installation.
     ==> Package distributor has shipped an updated version.
       What would you like to do about it ?  Your options are:
        Y or I  : install the package maintainer's version
        N or O  : keep your currently-installed version
    *** rsyslog.conf (Y/I/N/O/D/Z) [default=N] ? (按下 Enter)
    ...
    Samba server and utilities
    What do you want to do about modified configuration file smb.conf?
    keep the local version currently installed (选取本选项)
    
    ...
    Configuring openssh-server
    What do you want to do about modified configuration file sshd_config?
    keep the local version currently installed (选取本选项)
    
    ...
    460 packages are going to be removed.
    Removing the packages can take several hours.
     Continue [yN]  Details [d] (输入 y)
    
    ...
    To finish the upgrade, a restart is required.
    If you select 'y' the system will be restarted.
     Continue [yN] (输入 y)