目录
当前位置: 首页 > 文档资料 > Debian 参考手册 >

第 8 章 - Debian 小技巧

优质
小牛编辑
132浏览
2023-12-01

8.1 启动系统

关于系统启动提示的详细信息请参见 LDP BootPrompt-HOWTO


8.1.1 “我忘记了 root 密码!”(一)

只要能访问控制台键盘,不需要 root 密码也可以启动系统并以 root 帐号登录。 (这里假设没有 BIOS 密码或 lilo 之类的启动引导器密码用于控制系统启动。)

下面是一个不需要额外的启动盘或对 BIOS 启动设置进行修改的过程。这里的“Linux”是代表在 Debian 默认安装系统中启动 Linux 内核的标签。

lilo 的启动屏幕中,当 boot: 一出现时 (在某些系统中,您必须按 shift 键以阻止自动启动;如果 lilo 使用 framebuffer,您需要按 TAB 键才能看到自己输入的选项),就输入:

     boot: Linux init=/bin/sh

这会让系统启动内核并运行 /bin/sh 而非其标准的 init。现在你已获得 root 权限和一个 root shell。由于当前 / 是以只读方式挂载,而其它的硬盘分区均未挂载,故你必须完成下列步骤才能获得一个有适当功能的系统。

     init-2.03# mount -n -o remount,rw /
     init-2.03# mount -avt nonfs,noproc,nosmbfs
     init-2.03# cd /etc
     init-2.03# vi passwd
     init-2.03# vi shadow

(如果 /etc/passwd 文件中所有用户的第二个域的数据都为“x”,就表明系统使用了影子(shadow)密码,必须编辑 /etc/shadow。)要删除 root 密码,请编辑密码文件中第二个数据域,将它设置为空白。这样重启系统不用密码就能登录到 root。当系统启动进入 runlevel 1 时,Debian(至少是 Potato 以后的版本)需要密码,一些较老的版本则不需要。

/bin 下装一个小编辑器是个好习惯,因为有时 /usr 是无法访问的(参阅应急的编辑器, 第 11.2 节)。

另外可以安装 sash 软件包,当系统无法启动时,还可执行:

     boot: Linux init=/bin/sash

/bin/sh 不可用时,sash 可作为 sh 的交互式替代品,它是静态链接,内建了许多标准工具(在系统提示符下输入“help”可获得参考列表)。


8.1.2 “我忘记了 root 密码!”(二)

从急救盘启动系统。假设 /dev/hda3 是原始 root 分区,可用下面的方法编辑密码文件,与上述方法一样容易。

     # mkdir fixit
     # mount /dev/hda3 fixit
     # cd fixit/etc
     # vi shadow
     # vi passwd

与上面的方法相比,该方法的好处在于不需要知道 lilo 密码(如果有的话)。但如果系统没有预先设置为从软盘或 CD 启动,就需要访问 BIOS 的权限。


8.1.3 无法启动系统

没在安装过程中制作启动盘?没关系。如果 lilo 损坏了,从 Debian 安装套件中拿出启动盘,用它来启动系统。假设你的 root 分区在 /dev/hda12,你想进入 runlevel 3,在启动提示符后输入:

     boot: rescue root=/dev/hda12 3

接下来,系统使用软盘上的内核启动,你可登录到一个几乎拥有全部功能的系统了。(可能有少量特性或模块不可用。)

如果系统崩溃,亦可参阅为无法启动的系统安装软件包, 第 6.3.6 节

如果想做张自定义启动盘,参阅急救盘中的 readme.txt 文档。


8.1.4 “我不想直接启动到 X!”

unstable/sid 很有趣,但在启动进程中执行不稳定的 xdmgdmkdmwdm 会让你焦头烂额。

首先,在启动提示符后输入如下指令获得 root shell:

     boot: Linux vga=normal s

这里的 Linux 是你要启动的内核的标记,“vga=normal”告诉 lilo 在普通 VGA 屏幕下运行,“s”(或“S”)是传给 init 的参数,告诉它进入单用户模式。在提示符后输入 root 密码。

有多种方法禁用 X 启动 daemons:

  • 运行 update-rc.d -f ?dm remove ; update-rc.d ?dm stop 99 1 2 3 4 5 6 .

  • 在所有 /etc/init.d/?dm 文件的最前面加上“exit 0”。

  • 把所有的 /etc/rc2.d/S99?dm 文件改名为 /etc/rc2.d/K99?dm

  • 删除所有的 /etc/rc2.d/S99?dm 文件。

  • 运行 :>/etc/X11/default-display-manager

其中,rc2.d 中的数字必须与 /etc/inittab 中指定的 runlevel 一致。而 ?dm 的意思是你要将同一个命令运行多次,每次将其替换成 xdmgdmkdmwdm 中的一个。

在 Debian 下只有第一种方法是“唯一正确的方法”。最后一种方法比较简单但只适用于 Debian,而且还需要使用 dpkg-reconfigure 重新设置一次。其它方法都是通用的中 daemons 的方法。

你仍可在任何控制台 shell 中用 startx 命令启动 X。


8.1.5 其它用于启动提示符的技巧

使用 lilo 启动提示符,可指定系统启动到特定的 runlevel 和配置。详情参阅 BootPrompt-HOWTO (LDP)。

如果希望系统启动到 runlevel 4,可以 lilo 启动提示符后输入:

     boot: Linux 4

如果希望系统启动到正常功能的单用户模式,而且你知道 root 密码,可在 lilo 启动提示符后输入下列任一参数。

     boot: Linux S
     boot: Linux 1
     boot: Linux -s

如果希望系统以少于实际内存数的内存启动(也就是说机器有 64MB 内存,只分配 48MB 给系统使用),在 lilo启动提示符后输入:

     boot: Linux mem=48M

注意,不要指定大于实际内存数的内存,否则内核会崩溃。如果你有多于 64MB 的内存,如 128MB,应在系统启动时执行 mem=128M 或在 /etc/lilo.conf 中添加类似的命令行,否则旧内核或使用旧 BIOS 的主板将无法使用大于 64MB 的内存。


8.1.6 设置 GRUB 启动参数

GRUB 是 Hurd 项目开发的新型启动管理器,比 Lilo 更灵活,不过启动参数也与之稍有不同。

     grub> find /vmlinuz
     grub> root (hd0,0)
     grub> kernel /vmlinuz root=/dev/hda1
     grub> initrd /initrd
     grub> boot

请注意 Hurd 中的设备名:

     HURD/GRUB           Linux               MSDOS/Windows
      (fd0)               /dev/fd0            A:
      (hd0,0)             /dev/hda1           C: (usually)
      (hd0,3)             /dev/hda4           F: (usually)
      (hd1,3)             /dev/hdb4           ?

详情参阅 /usr/share/doc/grub/README.Debian.gz/usr/share/doc/grub-doc/html/


8.2 活动记录


8.2.1 记录 shell 活动

比起普通的个人电脑环境,Unix 环境的系统管理包含了更多细致的任务。必须掌握所有基本的配置方法以便进行系统故障恢复。基于 X11 的 GUI 配置工具看上去漂亮又好用,但不适用于紧急状况。

记录 shell 活动是个好习惯,特别是 root 用户。

Emacs:使用 M-x shell 在缓冲区中开始记录,使用 C-x C-w 将缓冲区中的记录写入文件。

Shell:使用 screen 命令和 screen 来定制控制台, 第 8.6.28 节 中描述的“^A H”;或者使用 script 命令。

     $ script
     Script started, file is typescript
      ... do whatever ...
      Ctrl-D
     $ col -bx <typescript >savefile
     $ vi savefile

还可使用下面的方法:

     $ bash -i 2>&1 | tee typescript

8.2.2 记录 X 活动

如果需要 X 应用程序的活动记录图,包括 xterm 屏显,可使用 gimp(GUI)。它可以对每个窗口或整个屏幕进行拍照。还可以使用 xwd(xbase-clients)、import(imagemagick) 和 scrot(scrot)。


8.3 拷贝及创建子目录

这些拷贝和归档命令提供系统和数据备份的基本功能。 在 the example scripts 中提供了一个名为 backup 的简单备份脚本例子。


8.3.1 拷贝整个子目录的基本命令

如果想重新整理文件组织结构,可使用下面的方法移动文件及文件链接:

     标准方法:
     # cp -a /source/directory /dest/directory # 要求 GNU cp
     # (cd /source/directory && tar cf - . ) | \
             (cd /dest/directory && tar xvfp - )
     如果包含硬链接,则需要更严谨的方法:
     # cd /path/to/old/directory
     # find . -depth -print0 | afio -p -xv -0a /mount/point/of/new/directory
     如果是远程操作:
     # (cd /source/directory && tar cf - . ) | \
             ssh user@host.dom (cd /dest/directory && tar xvfp - )
     如果没有链接文件:
     # scp -pr user1@host1.dom:/source/directory \
               user2@host2.dom:/dest/directory

其中,scp <==> rcpssh <==> rsh

下面的有关拷贝整个子目录的信息由 Manoj Srivastava srivasta@debian.org 发表于 debian-user@lists.debian.org。


8.3.2 cp

传统上,cp 并不能真正完成这个任务,因为它既没对符号链接进行区别对待,又不能保存硬链接。另一件需要注意的事就是稀疏文件(有洞的文件)。

GNU cp 克服了这缺陷,然而对于非 GNU 系统,cp 仍存在问题。而且使用 cp 无法生成小巧轻便的文档包。

     % cp -a . newdir

8.3.3 tar

Tar 克服了 cp 在处理符号链接时出现的问题,然而,cpio 可以处理特殊文件,传统的 tar 却不行。

对于某个有多重硬链接的文件,tar 的处理方法是只将其中一个链接拷贝到磁带上,所以日后你只能找回拷贝中所保留那个的链接所指的文件;cpio 会为每个链接做一个拷贝,日后你可以找回任意一个链接所指的文件。

在 Potato 和 Woody 中,操作 .bz2 文件的 tar 命令参数有所变化,所以请在脚本中使用 --bzip2 而不要简写为 -I(Potato)或 -j(Woody)。


8.3.4 pax

全新的,符合 POSIX(IEEE Std 1003.2-1992, pages 380–388 (section 4.48) and pages 936–940 (section E.4.48))标准的,众望所归的,轻便的文档包交互工具。pax可以读、写以及列出文档包的成员,并能拷贝文件目录层次。pax 的操作独立于特定的文档包格式,支持各种各样不同的文档包格式。

pax工具刚刚成形,还很新。

     # apt-get install pax
     $ pax -rw -p e . newdir
      or
     $ find . -depth  | pax -rw -p e  newdir

8.3.5 cpio

cpiocpiotar 文档包提取/放入文件。该文档包可以是硬盘上的另一个文件,也可以是磁带或管道。

     $ find . -depth -print0 | cpio --null --sparse -pvd new-dir

8.3.6 afio

afio 更善于处理 cpio 格式的文档包。通常它比 cpio 要快,且提供了更多磁带选项,并且能更友好的处理有讹误的输入数据。它支持交互式处理多卷文档包。用 afio 制作压缩文档包比压缩 tarcpio 文档包更安全。在备份处理脚本中 afio 是更佳的“文档处理引擎”。

     $ find . -depth -print0 | afio -px -0a new-dir

对所有的磁带备份我都使用 afio


8.4 差量备份与数据同步

要进行差异备份和数据同步可使用下列几种方法:

  • rcs:备份并进行历史记录,只支持文本。

  • rdiff-backup:备份并进行历史记录。支持链接。

  • pdumpfs:对文件系统进行备份和历史记录。支持链接。

  • rsync:单路同步。

  • unison:双路同步。

  • arch:多路同步服务器备份并进行历史记录,但包括“处于工作中的目录”。

  • subversion:多路同步服务器备份并进行历史记录,专用于 Apache。

有关将这些方法与文档包操作结合应用的讨论参阅拷贝及创建子目录, 第 8.3 节,有关自动进行备份的讨论参阅日程安排(cronat), 第 8.6.27 节

我只讲解三个较容易使用的工具。


8.4.1 使用 rdiff 进行差异备份

rdiff-backup 提供了简单好用的方法对任何文件包括链接进行历史差异备份。例如要对 ~/ 目录下的所有文件备份到 /mnt/backup

     $ rdiff-backup --include ~/tmp/keep --exclude ~/tmp  ~/ /mnt/backup

从该文档包中取出 3 天前的旧数据恢复到 ~/old 目录:

     $ rdiff-backup -r 3D /mnt/backup ~/old

参阅 rdiff-backup(1)


8.4.2 使用 pdumpfs 进行每日备份

pdumpfs 是一种简单的每日备份系统,与 Plan9 的 dumpfs 一样,它每天都保存系统快照。任何时候都可以用它来恢复到某天的系统状态。请使用 pdumpfscron 来备份你的 home 目录。

在目标目录中,pdumpfsYYYY/MM/DD 的方式来组织系统快照。 当 pdumpfs 第一次运行时,它将所有源文件拷贝到快照目录。从每二次运行起,pdumpfs 仅拷贝更新的或新建的文件,对于没有改变的文件用硬链接方式指向前一天的系统快照,以此来节省硬盘空间。

     $ pdumpfs src-dir dest-dir [dest-basename]

参阅 pdumpfs(8)


8.4.3 使用 RCS 进行定期差异备份

Changetrack 会定期对 RCS 文档包中基于文本格式的配置文件的变化进行记录。参阅 changetrack(1)

     # apt-get install changetrack
     # vi changetrack.conf

8.5 系统冻结恢复


8.5.1 中止一个进程

运行 top 看看什么进程的活动有异常。按“P”以 CPU 使用率排序,“M”以内存使用率排序,“k”可以中止一个进程。还有一种方法,使用 BSD风格的 ps aux | less 或 System V 风格的 ps -efH | less。System V 风格的排列会显示父进程 ID (PPID),这对中止出错的(死掉的)子进程十分有用。

知道了进程的 ID,就可使用 kill 中止(或发信号给)某个进程,killall 的作用正如其名一样。经常使用的信号有:

      1: HUP,重启 daemon
     15: TERM,普通中止
      9: KILL,强令中止

8.5.2 Alt-SysRq

内核编译选项“Magic SysRq key”提供系统强心针。在 i386 机器上按下 ALT-SysRq 组合键后,试试按下列各键 r 0 k e i s u b,奇迹产生了:

Un'r'aw 让键盘从 X 崩溃中重生。将控制台 loglevel 改为'0'以减少错误信息。sa'k'(system attention key)中止当前虚拟控制台的所有进程。t'e'rminate 中止当前终端除 init 外的所有进程。k'i'll中止除 init 外的所有进程。

'S'ync,'u'mount 和 re'b'oot 帮你逃离真正的险境。

本文写作之时,Debian 默认安装的内核并未将该选项编译进去,需要重新编译内核激活该功能。详情参阅 /usr/share/doc/kernel-doc-version/Documentation/sysrq.txt.gz/usr/src/kernel-version/Documentation/sysrq.txt.gz


8.6 记住这些可爱的小命令


8.6.1 Pager

less 就是默认的 pager(文件内容浏览器)。按“h”可获得帮助。它比 more 更有用。在 shell 启动脚本中运行 eval $(lesspipe)eval $(lessfile) 可以让 less 活力四射。详情参阅 /usr/share/doc/lessf/LESSOPEN。使用 -R 选项可输出生癖字符 and enables ANSI color escape sequences。参阅 less(1)

对于某些编码系统(EUC)w3m 可能是更好的选择。


8.6.2 释放内存

freetop 能让你了解内存资源的许多有用信息。别担心“Mem:”行中“used”的大小,看看它下面的数字(本例的数字是 38792)。

     $ free -k # 用 256MB 内存的机器
                  total       used       free     shared    buffers cached
     Mem:        257136     230456      26680      45736     116136 75528
     -/+ buffers/cache:      38792     218344
     Swap:       264996          0     264996

物理内存的准确大小可通过 grep '^Memory' /var/log/dmesg 得到,本例将显示“Memory: 256984k/262144k available (1652k kernel code, 412k reserved, 2944k data, 152k init)”。

     Total         = 262144k = 256M (1k=1024, 1M=1024k)
     Free to dmesg = 256984k = Total - kernel - reserved - data - init
     Free to shell = 257136k = Total - kernel - reserved - data

约有5MB内存系统不能使用,因为内核需要它。


8.6.3 设定时间(BIOS)

     # date MMDDhhmmCCYY
     # hwclock --utc --systohc
     # hwclock --show

设定系统时间和硬件时间为 MM/DD hh:mm, CCYY。显示时间为本地时间而硬件时间使用 UTC。

如果硬件(BIOS)时间设置为 GMT,在文件 /etc/default/rcS 中改变设置 UTC=yes


8.6.4 设定时间(NTP)

参考:Managing Accurate Date and Time HOWTO


8.6.4.1 拥有永久 Internet 连接的系统设置时间

设置系统时钟通过远程服务器自动对时:

     # ntpdate server

如果你的系统拥有永久的 Internet 连接,应该将该命令加入 /etc/cron.daily/


8.6.4.2 偶尔进行 Internet 连接的系统设置时间

使用chrony 软件包。


8.6.5 如何禁用屏幕保护程序

禁用屏幕保护程序,使用下面的命令。

对于 Linux 控制台:

     # setterm -powersave off

启动 kon2 (kanji)控制台可执行:

     # kon -SaveTime 0

运行X可执行:

     # xset s off
      或
     # xset -dpms
      或
     # xscreensaver-command -prefs

控制其它的控制台特征,请参阅相关 man 页面。 改变和显示终端行设置,请参阅 stty(1)


8.6.6 搜索系统管理数据库

Glibc提供了getent(1)搜索管理数据库的各类项目。例如passwd、group、hosts、services、protocols、networks。

     getent database [key ...]

8.6.7 禁用声音(响铃)

最直接的方法是拔掉 PC 喇叭。;-) 对于 Bash shell 可执行:

     echo "set bell-style none">> ~/.inputrc

8.6.8 控制台上的错误信息

不想看屏幕显示的错误信息,首选的方法是检查 /etc/init.d/klogd,在该脚本中设置 KLOGD="-c 3" 然后运行 /etc/init.d/klogd restart。另一种方法是执行 dmesg -n3

这儿是各种错误级别的含义:

  • 0: KERN_EMERG, 系统不可用

  • 1: KERN_ALERT, 必须立即执行

  • 2: KERN_CRIT, 紧急状态

  • 3: KERN_ERR, 错误状态

  • 4: KERN_WARNING, 警告状态

  • 5: KERN_NOTICE, 正常状态且十分重要

  • 6: KERN_INFO, 报告

  • 7: KERN_DEBUG, debug-level 信息

如果你很厌恶详细而无用的错误信息,可以试试这个小补丁 shutup-abit-bp6(位于 样例脚本子目录)。

另一个该看看的地方是 /etc/syslog.conf;,检查一下是否有信息记录被发送到了控制台设备。


8.6.9 正确设置控制台类型

在类 Unix 系统中,访问控制台屏幕通常要调用库例程,这就为用户提供了一种独立于终端的方式来优化字符的屏幕更新过程。参阅 ncurses(3X)terminfo(5)

在 Debian 系统中,有大量预定义项目:

     $ toe | less                  # 所有项目
     $ toe /etc/terminfo/ | less   # 用户可再配置的项目

你的选择可导出到环境变量 TERM

当登录到远程Debian系统时,如果 xterm 的 terminfo 项目在非 Debian 的 xterm 中失效,请将终端类型改为支持较少特性的版本如“xterm-r6”。 参阅 /usr/share/doc/libncurses5/FAQ。“dumb”是 terminfo 的最小公分母。


8.6.10 让控制台恢复正常状态

如果执行 cat some-binary-file 后屏幕一片混乱(当你输入命令时,无法看到正常的回显(echo)):

     $ reset

8.6.11 将 DOS 下的文本文件转换为 Unix 类型

将DOS文本文件(行尾=^M^J)转换成 Unix 文本文件(行尾=^J)。

     # apt-get install sysutils
     $ dos2unix dosfile

8.6.12 使用 recode 转化文本文件

下面将在 DOS、 Mac 和 Unix 的文本文件中转换行结尾格式:

     $ recode /cl../cr <dos.txt >mac.txt
     $ recode /cr.. <mac.txt >unix.txt
     $ recode ../cl <unix.txt >dos.txt

自由的 recode 在各种各样的字符集和界面中转换:

     $ recode charset1/surface1..charset2/surface2 \
       <input.txt >output.txt

使用的通用字符集设置是(参阅 Locales 简介, 第 9.7.3 节) [37] :

  • us — ASCII (7 bits)

  • l1 — ISO Latin-1 (ISO-8859-1, Western Europe, 8 bits)

  • EUCJP — EUC-JP for Japanese (Unix)

  • SJIS — Shift-JIS for Japanese (Microsoft)

  • ISO2022JP — Mail encoding for Japanese (7 bits)

  • u2 — UCS-2 (Universal Character Set, 2 bytes)

  • u8 — UTF-8 (Universal Transformation Format, 8 bits)

使用的通用界面 [38] :

  • /cr — Carriage return as end of line (Mac text)

  • /cl — Carriage return line feed as end of line (DOS text)

  • / — Line feed as end of line (Unix text)

  • /d1 — Human readable bytewise decimal dump

  • /x1 — Human readable bytewise hexidecimal dump

  • /64 — Base64 编码文本

  • /QP — Quoted-Printable 编码文本

更多信息,请参阅 info recode 中的相关描述。

有更多的专业转换工具:

  • 字符集转换:

    • iconv — 本地编码转换

    • konwert — 特殊编码转换

  • 二进制文件转换:

    • uuencodeuudecode — 用于 Unix

    • mimencode — 用于邮件


8.6.13 正规表达式的置换

将所有文件 FILES ...中的所有 FROM_REGEX 字段替换成 TO_TEXT 字段。

     $ perl -i -p -e 's/FROM_REGEX/TO_TEXT/g;' FILES ...

-i 表示“就地编辑”,-p 表示“在FILES...各文件中循环”。如果置换很复杂,应使用参数 -i.bak 而非 -i,这有助于出错恢复;它会将每个原始文件保存为以 .bak 为后缀的备份文件。


8.6.14 使用脚本来编辑文件

下面的脚本将删除 5–10 行以及 16–20 行。

     #!/bin/bash
     ed $1 <<EOF
     16,20d
     5,10d
     w
     q
     EOF

在此,ed 命令与 vi 命令模式下的是一样的,从外部编辑文件的方式使它更适于脚本化。


8.6.15 提取源文件修改部分合并到更新包

下面的操作将根据文件位置,提取源文件的修改部分并创建统一的 diff 文件 file.patch0file.patch1

     $ diff -u file.old file.new1 > file.patch0
     $ diff -u old/file new1/file > file.patch1

diff 文件(也称补丁文件)通常用于发送程序更新。收到的补丁文件可使用下面的方法更新另一个文件

     $ patch -p0 file < file.patch0
     $ patch -p1 file < file.patch1

如果有 3 个版本的源代码,使用 diff3 来合并效率更高:

     $ diff3 -m file.mine file.old file.yours > file

8.6.16 分割大文件

     $ split -b 650m file   # 将大文件分块成多个 650MB 的小文件
     $ cat x* >largefile    # 将所有小文件合并成一个大文件

8.6.17 从文本格式的表格中抽取数据

假设有一个文本文件名为 DPL,其中存放着所有前 Debian 项目领导人的名字和他们的上台日期,表格格式是以空格做为分隔的。

     Ian     Murdock   August  1993
     Bruce   Perens    April   1996
     Ian     Jackson   January 1998
     Wichert Akkerman  January 1999
     Ben     Collins   April   2001
     Bdale   Garbee    April   2002
     Martin  Michlmayr March   2003

Awk 经常用于从这类文件中提取数据。

     $ awk '{ print $3 }' <DPL                   # month started
     August
     April
     January
     January
     April
     April
     March
     $ awk '($1=="Ian") { print }' <DPL          # DPL called Ian
     Ian     Murdock   August  1993
     Ian     Jackson   January 1998
     $ awk '($2=="Perens") { print $3,$4 }' <DPL # When Perens started
     April 1996

象 Bash 这种 Shell 也能够用来分析这种文件:

     $ while read first last month year; do 
         echo $month
       done <DPL
     ... 跟第一个 Awk 例子有相同的输出

在这里,read 内建命令使用字符 $IFS (internal field separators 内部列分隔符)来将行分开为单词。

如果你改变 IFS 为 ":",你能够用 shell 漂亮的分析 /etc/passwd

     $ oldIFS="$IFS"   # 保存旧值
     $ IFS=":"
     $ while read user password uid gid rest_of_line; do
         if [ "$user" = "osamu" ]; then 
           echo "$user's ID is $uid"
         fi
       done < /etc/passwd
     osamu's ID is 1001
     $ IFS="$oldIFS"   # 恢复旧值

(如果使用 Awk 作同样的事情,使用 FS=":" 来设置列分隔符。)

shell 也使用 IFS 来分开参数扩展、命令替换和算术扩展的结果集。 但在被单引号或双引号引用的单词内,不会发生这种情况。 默认的 IFS 值是: <space>、 <tab> 和 <newline> 。

请小心使用这个 shell IFS 技巧。 当 shell 解释部分脚本作为它的输入时,奇怪的事情将会发生。

     $ IFS=":,"                        # 使用 ":" 和 "," 作为 IFS
     $ echo IFS=$IFS,   IFS="$IFS"     # echo 是 Bash 内建的
     IFS=  , IFS=:,
     $ date -R                         # 只是一个命令输出
     Sat, 23 Aug 2003 08:30:15 +0200
     $ echo $(date -R)                 # 子 shell --> 输入到主 shell
     Sat  23 Aug 2003 08 30 36 +0200
     $ unset IFS                       # 重设 IFS 为默认的
     $ echo $(date -R)
     Sat, 23 Aug 2003 08:30:50 +0200

8.6.18 精巧的管道命令辅助脚本

下列脚本做为管道的一部分十分有用。

     find /usr | egrep -v "/usr/var|/usr/tmp|/usr/local"
                          # 查找 /usr 下的所有文件,排除某些文件
     xargs -n 1 command   # 将所有项作为标准输入来执行命令
     xargs -n 1 echo |    # 将空格隔离的项分开为行
     xargs echo      |    # 合并所有的行到一行里面
     grep -e pattern|     # 提取含有 pattern 的行
     cut -d: -f3 -|
             # 提取用 : 分开的第 3 列(比如说 passwd 文件)
     awk '{ print $3 }' | # 提取用空格分开的第 3 列
     awk -F'\t' '{ print $3 }' |
            # 提取用 tab 分开的第 3 列
     col -bx |            # 删除退格键,扩展 tab 为空格
     expand -|            # 扩展 tab
     sort -u|             # 排序并删除重复行
     
     tr '\n' ' '|         # 将多行连接为一行
     tr '\r' ''|          # 删除 CR
     tr 'A-Z' 'a-z'|      # 转化大写字母为小写
     sed 's/^/# /'|       # 将每行变为注释
     sed 's/\.ext//g'|    # 删除 .ext
     sed  -n -e 2p|       # 显示第 2 行
     head -n 2 -|         # 显示头两行
     tail -n 2 -|         # 显示最后两行

8.6.19 循环每一个文件的脚本片段

下面的方法将循环处理匹配 *.ext 的每一个文件,确保适当处理文件名包含空格的奇怪文件,并且执行相同的操作。

  • Shell 循环 (在 PS2=" " 时使用多行格式的例子。 如果在一行内输入这些命令,需要在每一个换行处加一个分号。):

         for x in *.ext; do
           if test -f "$x"; then
             command "$x"
           fi
         done
    
  • findxargs 结合:

         find . -type f -maxdepth 1 -name '*.ext' -print0 | \
          xargs -0 -n 1 command
    
  • -exec 选项的 find 和一个命令结合:

         find . -type f -maxdepth 1 -name '*.ext' \
          -exec command '{}' \;
    
  • -exec 选项的 find 和一个短的 shell 脚本结合:

         find . -type f -maxdepth 1 -name '*.ext' \
          -exec sh -c "command '{}' && echo 'successful'" \;
    

8.6.20 短小的 Perl 脚本

虽然任何 Awk 脚本均可使用 a2p(1) 自动重写成 Perl, 但最好用手工的方法将一行 Awk 脚本转化为一行 perl 脚本。例如:

     awk '($2=="1957") { print $3 }' |

与下列任意一行相当:

     perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |
     perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |
     perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |
     perl -lane 'print $F[2] if $F[1] eq "1957"' |

其实上面各行中所有 perl 参数中的空格均可去掉,这得益于 Perl 的数字字符串自动转换功能。

     perl -lane 'print$F[2]if$F[1]eq+1957' |

有关命令行参数的信息可参阅 perlrun(1),在 http://perlgolf.sourceforge.net 有更多令人着魔的 Perl 脚本,你会感兴趣的。


8.6.21 从网页上获取文本或邮件列表文档

下面的操作将网页转化为文本文件。从网上拷贝配置文件时十分有用。

     $ lynx -dump http://www.remote-site.com/help-info.html >textfile

linksw3m 也可以这么用,只是生成的文本样式可能略有不同。

如果是邮件列表文档,可使用 munpack 从文本获得 mime 内容。


8.6.22 打印网页

下面的操作将网页内容打印成 PostScript 文件或发送到打印机。

     $ apt-get install html2ps
     $ html2ps URL | lpr

参阅lpr/lpd, 第 3.6.1 节。还可使用 a2psmpage 软件包生成 PostScript 文件。


8.6.23 打印帮助页面

下面的操作将帮助页面打印成PostScript文件或发送到打印机。

     $ man -Tps some-manpage | lpr
     $ man -Tps some-manpage | mpage -2 | lpr

8.6.24 合并两个 PostScript 或 PDF 文件

可以将两个 PostScript 文件或 PDF 文件合并。

     $ gs -q -dNOPAUSE -dBATCH -sDEVICE=pswrite \
       -sOutputFile=bla.ps -f foo1.ps foo2.ps
     $ gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
       -sOutputFile=bla.pdf -f foo1.pdf foo2.pdf

8.6.25 命令耗时

显示某进程的耗时

     # time some-command >/dev/null
     real    0m0.035s       # 挂钟时间(过去的真实时间)
     user    0m0.000s       # 用户模式时间
     sys     0m0.020s       # 核心模式时间

8.6.26 nice 命令

使用 nice(来自 GNU shellutils 软件包)可设置命令启动时的 nice 值。renice(bsdutils)和 top 可以重设进程的 nice 值。nice 值为 19 代表最慢的(优先级最低的)进程;负值就“not-nice”,如 -20 代表非常快的(优先级高的)进程。只有超级用户可以设定负 nice 值。

     # nice  -19 top                                         # very nice
     # nice --20 cdrecord -v -eject speed=2 dev=0,0 disk.img # very fast

有时极端的 nice 值对系统弊大于利,所以使用该命令要小心。


8.6.27 日程安排(cronat)

在 Linux 下使用 cronat 进行任务日程安排。参阅 at(1)crontab(5)crontab(8)

执行命令 crontab -e 创建或编辑 crontab 文件,为规律事务(按周期循环的事务)安排日程。下面的一个 crontab 文件样例:

     # use /bin/sh to run commands, no matter what /etc/passwd says
     SHELL=/bin/sh
     # mail any output to `paul', no matter whose crontab this is
     MAILTO=paul
     # Min Hour DayOfMonth Month DayOfWeek command (Day... are OR'ed)
     # run at 00:05, every day
     5  0  *  * *   $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
     # run at 14:15 on the first of every month -- output mailed to paul
     15 14 1  * *   $HOME/bin/monthly
     # run at 22:00 on weekdays(1-5), annoy Joe. % for newline, last % for cc:
     0 22 *   * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%.%%
     23 */2 1 2 *   echo "run 23 minutes after 0am, 2am, 4am ..., on Feb 1"
     5  4 *   * sun echo "run at 04:05 every sunday"
     # run at 03:40 on the first Monday of each month
     40 3 1-7 * *   [ "$(date +%a)" == "Mon" ] && command -args

执行 at 命令为偶然任务(只执行一次的任务)安排日程:

     $ echo 'command -args'| at 3:40 monday

8.6.28 用 screen 来定制控制台

screen 程序允许在单一的物理终端或终端模拟窗口运行多个伪终端,每个伪终端都拥有自己的交互式 shell。即便可以使用 Linux 伪终端或多个 xterm 窗口,研究一下如何设置 screen 丰富的特性仍很有益,这些特性包括:

  • 回溯历史显示,

  • 拷贝和粘贴,

  • 输出到日志,

  • 图形入口,

  • 将终端与整个 screen 会话分离,稍后再连接。


8.6.28.1 远程访问方案

如果你经常从远程终端登录到 Linux 机器或使用 VT100 终端程序,screendetach(分离)特性将简化你的生活。

  • 通过拔号连接登录,运行了一个非常复杂的 screen 会谈,打开了好几个窗口,有编辑器和其它一些程序。

  • 突然你需要离开终端一下,但你并不想挂断连接中止工作。

  • 输入^A d离开会话,然后登出系统。(或者更简单些,输入^A DD离开会话并自动登出系统)

  • 当你回来时,需要再次登录,可输入命令 screen -rscreen 会如魔法般地重新连接上所有打开的窗口。


  • 8.6.28.2 典型的 screen 命令

    一但打开了 screen 程序,除了命令按键(默认为^A)所有的键盘输入都被送到当前窗口,所有的 screen 命令均按特定方式输入:^A加一个单键命令[加一些参数]的。常用的命令有:

         ^A ?     显示帮助屏幕(显示命令集)
         ^A c     创建并切换到新窗口
         ^A n     跳到下一个窗口
         ^A p     跳到上一个窗口
         ^A 0     跳到 0 号窗口
         ^A w     显示窗口列表
         ^A a     将 Ctrl-A 做为键盘输入发送到当前窗口
         ^A h     对当前窗口做硬拷贝写入到文件
         ^A H     开始/中止将当前窗口事件记录到文件
         ^A ^X    锁定终端(密码保护)
         ^A d     从终端分离屏幕会话
         ^A DD    分离屏幕会话并退出登录
    

    以上只是 screen 命令的一个很小的子集。只要是你认为 screen 能干的事,没准它真就可以!详情参阅 screen(1)


    8.6.28.3 screen 会话中的退格键和Ctrl-H

    在运行 screen 时,如果发现退格键和 / 或 Ctrl-H 无法正常工作,可编辑/etc/screenrc,找到这行:

         bindkey -k kb stuff "\177"
    

    将这注释掉(例如在句首添加“#”)。


    8.6.28.4 X 下与 screen 等价的程序

    找找 xmove。参阅 xmove(1)


    8.6.29 网络测试基础

    安装 netkit-pingtraceroutednsutilsipchains(适用于 2.2 版内核)、iptables(适用于 2.4 版内核) 和 net-tools 软件包,然后执行:

         $ ping yahoo.com            # 检查 Internet 连接
         $ traceroute yahoo.com      # 跟踪 IP 数据包
         $ ifconfig                  # 检查主机设置
         $ route -n                  # 检查路由设置
         $ dig [@dns-server.com] host.dom [{a|mx|any}] |less
               # 检查dns-server.comhost.dom DNS 记录
               # 查找{a|mx|any}记录
         $ ipchains  -L -n |less     # 检查包过滤(2.2 kernel)
         $ iptables -L -n |less      # 检查包过滤(2.4 kernel)
         $ netstat -a                # 查找系统上所有打开的端口
         $ netstat -l --inet         # 查找系统监听的端口
         $ netstat -ln --tcp         # 查找系统监听的 TCP 端口(端口数字)
    

    8.6.30 从本地缓冲池中清空(flush)邮件

    从本地缓冲池中清空邮件:

         # exim -q    # 清空待读邮件
         # exim -qf   # 清空所有邮件
         # exim -qff  # 清空冻结邮件
    

    -qff 选项用在 /etc/ppp/ip-up.d/exim 脚本中效果更好。 在 Sarge 中,使用 exim4 代替 exim


    8.6.31 删除本地缓冲池中的冻结邮件

    删除本地缓冲池中的冻结邮件并返回出错信息:

         # exim -Mg `mailq | grep frozen | awk '{ print $3 }'`
    

    在 Sarge 中,使用 exim4 代替 exim


    8.6.32 再分发 mbox 中的信件

    如果 home 目录没有空间继续处理邮件,procmail 将失败, 就需要对磁盘空间进行扩容,扩容完成后需要手工分发 /var/mail/username 目录中的邮件到 home 目录中的分类邮箱,执行:

         # /etc/init.d/exim stop
         # formail -s procmail </var/mail/username
         # /etc/init.d/exim start
    

    在 Sarge 中,使用 exim4 代替 exim


    8.6.33 清空文件内容

    要清空某些文件如日志文件的内容,千万不要使用 rm 删除文件然后再创建一个新的空文件,因为在两次操作的间隔,系统可能需要访问该文件。下面是清空文件内容的安全方法:

         $ :>file-to-be-cleared
    

    8.6.34 空文件

    下面的命令可以创建空文件:

         $ dd if=/dev/zero    of=filename bs=1k count=5 # 5KB 零内容
         $ dd if=/dev/urandom of=filename bs=1M count=7 # 7MB 随机内容
         $ touch filename #  创建一个 0 B 大小的文件 (如果文件存在,更新该文件的修改时间)
    

    例如,最实用的用法是从 Debian 启动软盘的 shell 中执行下列命令将硬盘 /dev/hda 的内容完全清空。

         # dd if=/dev/urandom of=/dev/hda ; dd if=/dev/zero of=/dev/hda
    

    8.6.35 chroot

    chroot 程序,chroot(8),不需要重启系统,就可以在单独的系统上同时运行多个不同的 GNU/Linux 环境。

    还可以在较快主机的 chroot 下运行某些需耗大量系统资源内存的程序如 apt-getdselect,并将较慢子机的硬盘通过 NFS 方式挂载到主机,开放读/写权限,在主机上以 chroot 方式操作子机。


    8.6.35.1 用 chroot 来运行不同版本的 Debian

    在 Sarege 中使用 debootstrap 命令很容易构造 chroot Debian 体系。对于 Sarge 的后续发行版,用 cdebootstrap 命令加上适当的选项来代替 debootstrap。例如,在一台拥有快速 Internet 连接的机器的 /sid-root 下创建一个 Sid chroot:

         main # cd / ; mkdir /sid-root
         main # debootstrap sid /sid-root http://ftp.debian.org/debian/
         ... 看它下载整个系统
         main # echo "proc-sid /sid-root/proc proc none 0 0" >> /etc/fstab
         main # mount proc-sid /sid-root/proc -t proc
         main # cp /etc/hosts /sid-root/etc/hosts
         main # chroot /sid-root /bin/bash
         chroot # cd /dev; /sbin/MAKEDEV generic ; cd -
         chroot # apt-setup # 创建 /etc/apt/sources.list 文件
         chroot # vi /etc/apt/sources.list # 将源指向 unstable
         chroot # dselect  # 可以使用 aptitude,安装 mc 和 vim :-)
    

    现在你就拥有了一个全功能 Debian 子系统,可以尽情享受而不必担心主 Debian 受到不利影响。

    debootstrap 应用技巧还可以实现在没有 Debian 安装盘的情况下,从另一个 GNU/Linux 发行版下安装 Debian。参阅 http://www.debian.org/releases/stable/i386/apcs04


    8.6.35.2 设置 chroot 登录

    输入 chroot /sid-root /bin/bash 非常简单,但这将保留当前的所有环境变量,你可能并不希望这样并且有时还会出问题。更好的方法是,在别的虚拟终端上执行另一个登录进程,登录到 chroot 目录。

    在默认的 Debian 系统中,从 tty1tty6 运行 Linux 控制台,tty7 运行 X Window 系统,在本例中,我们将 tty8 设置成 chroot 控制台。按照chroot 来运行不同版本的 Debian, 第 8.6.35.1 节 中的描述创建好 chroot 系统后,就可以在主系统的 root shell 中输入:

         main # echo "8:23:respawn:/usr/sbin/chroot /sid-root "\
                "/sbin/getty 38400 tty8"  >> /etc/inittab
         main # init q    # 重启 init
    

    8.6.35.3 配置 chroot 下的 X

    想在 chroot 下安全地运行最新版的 X 和 GNOME 吗?完全可以!下面的例子将实现在虚拟终端 vt9 下运行 GDM。

    首先,按照chroot 来运行不同版本的 Debian, 第 8.6.35.1 节中描述的方法安装好 chroot 系统,从主系统的 root 下拷贝关键配置文件到 chroot 系统。

         main # cp /etc/X11/XF86Config-4 /sid-root/etc/X11/XF86Config-4
         main # chroot /sid-root # or use chroot console
         chroot # cd /dev; /sbin/MAKEDEV generic ; cd -
         chroot # apt-get install gdm gnome x-window-system
         chroot # vi /etc/gdm/gdm.conf # do s/vt7/vt9/ in [servers] section
         chroot # /etc/init.d/gdm start
    

    在此,编辑 /etc/gdm/gdm.conf,使其在 vt7vt9 上创建虚拟终端。

    现在可以很容易地能过切换 Linux 虚拟终端来实现在主系统的 X 环境和 chroot 系统的 X 环境之间转换,例如使用 Ctrl-Alt-F7 和 Ctrl-Alt-F9。酷吧!

    [FIXME] 在 chroot 系统下 gdm 的 init 脚本中添加一条注释和一条链接。


    8.6.35.4 使用 chroot 来运行其它发行版

    很容易创建一个包含其它发行版的 chroot 环境。使用其它发行版的安装程序将它们安装到单独的硬盘分区中。例如 root 分区位于 /dev/hda9

         main # cd / ; mkdir /other-dist
         main # mount -t ext3 /dev/hda9 /other-dist
         main # chroot /other-dist /bin/bash
    

    接下来按照 chroot 来运行不同版本的 Debian, 第 8.6.35.1 节设置 chroot 登录, 第 8.6.35.2 节配置 chroot 下的 X, 第 8.6.35.3 节 处理。


    8.6.35.5 使用 chroot 来编译软件包

    这儿有一个很特殊的 chroot 软件包 pbuilder,它构造一个 chroot 系统并在其中编译软件包。该体系可用于检查软件包编译时关联关系是否正确,并确保编译生成的软件包中没有不必要的或错误的关联关系。


    8.6.36 怎样检查硬链接

    检查两个文件是否是指向同一个文件的两个硬链接:

          
         $ ls -li file1 file2
    

    8.6.37 mount 硬盘上的镜像文件

    如果 file.img 文件是硬盘内容的镜像文件,而且原始硬盘的配置参数为 xxxx = (bytes/sector) * (sectors/cylinder),那么,下面的命令将其挂载到 /mnt

         # mount -o loop,offset=xxxx file.img /mnt
    

    注意绝大部分的硬盘都是 512 bytes/sector。


    8.6.38 Samba

    获取 Windows 文件的基本方法:

         # mount -t smbfs -o username=myname,uid=my_uid,gid=my_gid \
                 //server/share /mnt/smb  # 挂载 Windows 的文件到 Linux
         # smbmount //server/share /mnt/smb \
                 -o "username=myname,uid=my_uid,gid=my_gid"
         # smbclient -L 192.168.1.2 # 列出某个计算机的共享目录
    

    可从 Linux 检查 Samba网上邻居:

         # smbclient -N -L ip_address_of_your_PC | less
         # nmblookup -T "*"
    

    8.6.39 外来文件系统的操作工具

    Linux 内核支持多种外来文件系统,想访问它们只需将其挂载到合适的文件系统下就行了。对某些文件系统,还提供专门工具不需要挂载,只依靠用户空间的程序,不需要内核提供文件系统支持,就能完成访问。

    • mtools: for MSDOS filesystem (MS-DOS, Windows)

    • cpmtools: for CP/M filesystem

    • hfsutils: for HFS filesystem (native Macintosh)

    • hfsplus: for HFS+ filesystem (modern Macintosh)

    对于创建和检查 MS-DOS FAT 文件系统 dosfstools 非常有用。


    8.7 需要注意的典型错误

    这里有一些危险行为的例子。如果你是使用特权账号 root 的话,负面影响将会更大。


    8.7.1 rm -rf .*

    在象"rm -rf .*" 的命令行参数中使用通配符文件名,有可能造成危险的结果, 因为 ".*" 扩展为 "." 和 ".."。 比较幸运的是,在 Debian 发行版中,当前版本的 "rm" 命令会检查文件名参数的健全性,会拒绝删除 "." 和 ".."。 但这种检查并不一定在其它地方存在。 尝试下面的操作来参看通配符文件名是怎样工作的。

    • "echo ." : 列出当前目录自身

    • "echo *" : 列出当前目录下所有不以点开头的文件和目录

    • "echo .[^.]*" : 列出当前目录下所有以点开头的文件和目录

    • "echo .*" : 列出父目录下的所有东西和父目录自身


    8.7.2 rm /etc/passwd

    由于你的过失,丢失象 /etc/passwd 这样的重要文件,是一件非常痛苦的事。Debian 系统周期性的将他们备份到 /var/backups/。 当你恢复这些文件的时候,你需要设置适当的权限。

         # cp /var/backups/passwd /etc/passwd
         # chmod 644 /etc/passwd
    

    参阅 恢复软件包选择状态的数据,第 6.3.4 节