
了解这些设备的最基本要求就是对 每个设备文件的含义了如指掌,下面就医列表的形式列出常见的设备文件以及相应的含义(比较偏僻的就省略了):
----------------------------------------------------------------------
主设备号 设备类型
次设备号=文件名 简要说明
----------------------------------------------------------------------
0 未命名设备(例如:挂载的非设备)
0 = 未空设备号保留
1 char 内存设备
1 = /dev/mem 直接存取物理内存
2 = /dev/kmem 存取经过内核虚拟之后的内存
3 = /dev/null 空设备。任何写入都将被直接丢弃,任何读取都将得到EOF。
4 = /dev/port 存取 I/O 端口
5 = /dev/zero 零字节源,只能读取到无限多的零字节。
7 = /dev/full 满设备。任何写入都将失败,并把errno设为ENOSPC以表示没有剩余空间。
8 = /dev/random 随机数发生器。完全由用户的输入来产生随机数。
如果用户停止所有动作,则停止产生新的随机数。
9 = /dev/urandom 更快,但是不够安全的随机数发生器。尽可能由用户的输入来产生随机数,
如果用户停止所有动作,则把已经产生的随机数做为种子来产生新的随机数。
10 = /dev/aio 异步 I/O 通知接口
11 = /dev/kmsg 任何对该文件的写入都将作为 printk 的输出
1 block RAM disk
0 = /dev/ram0 第1个 RAM disk (initrd只能使用ram0)
1 = /dev/ram1 第2个 RAM disk
...
200 = /dev/ram200 第200个 RAM disk
4 char TTY(终端)设备
0 = /dev/tty0 当前虚拟控制台
1 = /dev/tty1 第1个虚拟控制台
...
63 = /dev/tty63 第63个虚拟控制台
4 block 如果根文件系统以是以只读方式挂载的,那么就不可能创建真正的设备节点,
此时就使用该设备作为动态分配的主(major)设备的别名
0 = /dev/root
5 char 其他 TTY 设备
0 = /dev/tty 当前 TTY 设备
1 = /dev/console 系统控制台
2 = /dev/ptmx 所有 PTY master 的复用器
7 char 虚拟控制台捕捉设备(这些设备既允许读也允许写)
0 = /dev/vcs 当前虚拟控制台(vc)的文本内容
1 = /dev/vcs1 tty1 的文本内容
...
63 = /dev/vcs63 tty63 的文本内容
128 = /dev/vcsa 当前虚拟控制台(vc)的文本/属性内容
129 = /dev/vcsa1 tty1 的文本/属性内容
...
191 = /dev/vcsa63 tty63 的文本/属性内容
7 block 回环设备(用一个普通的磁盘文件来模拟一个块设备)
对回环设备的绑定由 mount(8) 或 losetup(8) 处理
0 = /dev/loop0 第1个回环设备
1 = /dev/loop1 第2个回环设备
...
8 block SCSI 磁盘(0-15)
0 = /dev/sda 第1个 SCSI 磁盘(整个磁盘)
16 = /dev/sdb 第2个 SCSI 磁盘(整个磁盘)
32 = /dev/sdc 第3个 SCSI 磁盘(整个磁盘)
...
240 = /dev/sdp 第16个 SCSI 磁盘(整个磁盘)
分区表示方法如下(以第3个 SCSI 磁盘为例)
33 = /dev/sdc1 第1个分区
34 = /dev/sdc2 第2个分区
...
47 = /dev/sdc15 第15个分区
对于Linux/i386来说,分区1-4是主分区,5-15是逻辑分区。
9 block Metadisk(RAID)设备
0 = /dev/md0 第1组 metadisk
1 = /dev/md1 第2组 metadisk
...
metadisk 驱动用于将同一个文件系统分割到多个物理磁盘上。
10 char 非串口鼠标,各种杂项设备和特性
1 = /dev/psaux PS/2鼠标
131 = /dev/temperature 机器内部温度
134 = /dev/apm_bios APM(高级电源管理) BIOS
135 = /dev/rtc 实时时钟(Real Time Clock)
144 = /dev/nvram 非易失配置 RAM
162 = /dev/smbus 系统管理总线(System Management Bus)
164 = /dev/ipmo Intel的智能平台管理(Intelligent Platform Management)接口
173 = /dev/ipmikcs 智能平台管理(Intelligent Platform Management)接口
175 = /dev/agpgart AGP图形地址重映射表(Graphics Address Remapping Table)
182 = /dev/perfctr 性能监视计数器
183 = /dev/hwrng 通用硬件随机数发生器
184 = /dev/cpu/microcode CPU微代码更新接口
186 = /dev/atomicps 进程状态数据的原子快照
188 = /dev/smbusbios SMBus(系统管理总线) BIOS
200 = /dev/net/tun TAP/TUN 网络设备(TAP/TUN以软件的方式实现了网络设备)
TAP模拟了以太网帧(第二层),TUN模拟了IP包(第三层)。
202 = /dev/emd/ctl 增强型 Metadisk RAID (EMD) 控制器
220 = /dev/mptctl Message passing technology (MPT) control
223 = /dev/input/uinput 用户层输入设备驱动支持
227 = /dev/mcelog X86_64 Machine Check Exception driver
228 = /dev/hpet HPET driver
229 = /dev/fuse Fuse(用户空间的虚拟文件系统)
231 = /dev/snapshot 系统内存快照
232 = /dev/kvm 基于内核的虚构机(基于AMD SVM和Intel VT硬件虚拟技术)
11 block SCSI CD-ROM 设备
0 = /dev/scd0 第1个 SCSI CD-ROM
1 = /dev/scd1 第2个 SCSI CD-ROM
...
13 char 核心输入设备
32 = /dev/input/mouse0 第1个鼠标
33 = /dev/input/mouse1 第2个鼠标
...
62 = /dev/input/mouse30 第31个鼠标
63 = /dev/input/mice 所有鼠标的统一
64 = /dev/input/event0 第1个事件队列
65 = /dev/input/event1 第2个事件队列
...
95 = /dev/input/event1 第32个事件队列
21 char 通用 SCSI 设备(通常是SCSI光驱)
0 = /dev/sg0 第1个通用 SCSI 设备
1 = /dev/sg1 第2个通用 SCSI 设备
...
29 char 通用帧缓冲(frame buffer)设备
0 = /dev/fb0 第1个帧缓冲设备
1 = /dev/fb1 第2个帧缓冲设备
...
31 = /dev/fb31 第32个帧缓冲设备
30 char iBCS-2 兼容设备
0 = /dev/socksys 套接字访问接口
1 = /dev/spx SVR3 本地 X 接口
32 = /dev/inet/ip 网络访问接口
33 = /dev/inet/icmp
34 = /dev/inet/ggp
35 = /dev/inet/ipip
36 = /dev/inet/tcp
37 = /dev/inet/egp
38 = /dev/inet/pup
39 = /dev/inet/udp
40 = /dev/inet/idp
41 = /dev/inet/rawip
此外,iBCS-2 还需要下面的连接必须存在
/dev/ip ->/dev/inet/ip
/dev/icmp ->/dev/inet/icmp
/dev/ggp ->/dev/inet/ggp
/dev/ipip ->/dev/inet/ipip
/dev/tcp ->/dev/inet/tcp
/dev/egp ->/dev/inet/egp
/dev/pup ->/dev/inet/pup
/dev/udp ->/dev/inet/udp
/dev/idp ->/dev/inet/idp
/dev/rawip ->/dev/inet/rawip
/dev/inet/arp ->/dev/inet/udp
/dev/inet/rip ->/dev/inet/udp
/dev/nfsd ->/dev/socksys
/dev/X0R ->/dev/null
36 char Netlink 支持
0 = /dev/route 路由, 设备更新, kernel to user
3 = /dev/fwmonitor Firewall packet 复制
59 char sf 防火墙模块
0 = /dev/firewall 与 sf 内核模块通信
65 block SCSI 磁盘(16-31)
0 = /dev/sdq 第17个 SCSI 磁盘(整个磁盘)
16 = /dev/sdr 第18个 SCSI 磁盘(整个磁盘)
32 = /dev/sds 第19个 SCSI 磁盘(整个磁盘)
...
240 = /dev/sdaf 第32个 SCSI 磁盘(整个磁盘)
66 block SCSI 磁盘(32-47)
0 = /dev/sdag 第33个 SCSI 磁盘(整个磁盘)
16 = /dev/sdah 第34个 SCSI 磁盘(整个磁盘)
32 = /dev/sdai 第35个 SCSI 磁盘(整个磁盘)
...
240 = /dev/sdav 第48个 SCSI 磁盘(整个磁盘)
89 char I2C 总线接口
0 = /dev/i2c-0 第1个 I2C 适配器
1 = /dev/i2c-1 第2个 I2C 适配器
...
98 block 用户模式下的虚拟块设备(分区处理方式与 SCSI 磁盘相同)
0 = /dev/ubda 第1个用户模式块设备
16 = /dev/udbb 第2个用户模式块设备
...
103 block 审计(Audit)设备
0 = /dev/audit 审计(Audit)设备
128-135 char Unix98 PTY master
这些设备不应当存在设备节点,而应当通过 /dev/ptmx 接口访问。
136-143 char Unix98 PTY slave
这些设备节点是自动生成的(伴有适当的权限和模式),不能手动创建。
方法是通过使用适当的 mount 选项(通常是:mode=0620,gid=<"tty"组的gid>)
将 devpts 文件系统挂载到 /dev/pts 目录即可。
0 = /dev/pts/0 第1个 Unix98 PTY slave
1 = /dev/pts/1 第2个 Unix98 PTY slave
...
153 block Enhanced Metadisk RAID (EMD) 存储单元(分区处理方式与 SCSI 磁盘相同)
0 = /dev/emd/0 第1个存储单元
1 = /dev/emd/0p1 第1个存储单元的第1个分区
2 = /dev/emd/0p2 第1个存储单元的第2个分区
...
15 = /dev/emd/0p15 第1个存储单元的第15个分区
16 = /dev/emd/1 第2个存储单元
32 = /dev/emd/2 第3个存储单元
...
240 = /dev/emd/15 第16个存储单元
180 char USB 字符设备
96 = /dev/usb/hiddev0 第1个USB人机界面设备(鼠标/键盘/游戏杆/手写版等人 *** 作计算机的设备)
...
111 = /dev/usb/hiddev15 第16个USB人机界面设备
180 block USB 块设备(U盘之类)
0 = /dev/uba 第1个USB 块设备
8 = /dev/ubb 第2个USB 块设备
16 = /dev/ubc 第3个USB 块设备
...
192 char 内核 profiling 接口
0 = /dev/profile Profiling 控制设备
1 = /dev/profile0 CPU 0 的 Profiling 设备
2 = /dev/profile1 CPU 1 的 Profiling 设备
...
193 char 内核事件跟踪接口
0 = /dev/trace 跟踪控制设备
1 = /dev/trace0 CPU 0 的跟踪设备
2 = /dev/trace1 CPU 1 的跟踪设备
...
195 char Nvidia 图形设备(比如显卡)
0 = /dev/nvidia0 第1个 Nvidia 卡
1 = /dev/nvidia1 第2个 Nvidia 卡
...
255 = /dev/nvidiactl Nvidia 卡控制设备
202 char 特定于CPU模式的寄存器(model-specific register,MSR)
0 = /dev/cpu/0/msr CPU 0 的 MSRs
1 = /dev/cpu/1/msr CPU 1 的 MSRs
...
203 char CPU CPUID 信息
0 = /dev/cpu/0/cpuid CPU 0 的 CPUID
1 = /dev/cpu/1/cpuid CPU 1 的 CPUID
...
===================================================================
这部分详细说明一些应该或可能存在于 /dev 目录之外的文件。
链接最好使用与这里完全相同的格式(绝对路径或相对路径)。
究竟是使用硬链接(hard)还是软连接(symbolic)取决于不同的设备。
必须的链接
必须在所有的系统上都存在这些连接:
链接 目标 链接类型 简要说明
/dev/fd /proc/self/fd symbolic 文件描述府
/dev/stdin fd/0 symbolic 标准输入文件描述府
/dev/stdout fd/1 symbolic 标准输出文件描述符
/dev/stderr fd/2 symbolic 标准错误文件描述符
/dev/nfsd socksys symbolic 仅为 iBCS-2 所必须
/dev/X0R null symbolic 仅为 iBCS-2 所必须
[注意] /dev/X0R 是 <字母 X>-<数字 0>-<字母 R>
推荐的链接
推荐在所有的系统上都存在这些连接:
链接 目标 链接类型 简要说明
/dev/core /proc/kcore symbolic 为了向后兼容
/dev/ramdisk ram0 symbolic 为了向后兼容
/dev/ftape qft0 symbolic 为了向后兼容
/dev/bttv0 video0 symbolic 为了向后兼容
/dev/radio radio0 symbolic 为了向后兼容
/dev/i2o* /dev/i2o/* symbolic 为了向后兼容
/dev/scd? sr? hard 代替 SCSI CD-ROM 的名字
本地定义的链接
下面的链接很可能需要根据机器的实际硬件配置创建其中的一部分甚至全部。
这些链接仅仅是为了迎合习惯用法,它们既非必须也非推荐。
链接 目标 链接类型 简要说明
/dev/mouse mouse port symbolic 当前鼠标
/dev/tape tape device symbolic 当前磁带
/dev/cdrom CD-ROM device symbolic 当前CD-ROM
/dev/cdwriter CD-writer symbolic 当前CD-writer
/dev/scanner scanner symbolic 当前扫描仪
/dev/modem modem port symbolic 当前调制解调器
/dev/root root device symbolic 当前根文件系统所在设备
/dev/swap swap device symbolic 当前swap所在设备
/dev/modem 不应当用于能够同时支持呼入和呼出的modem,因为往往会导致锁文件问题。
如果存在 /dev/modem ,那么它应当指向一个恰当的主 TTY 设备。
对于SCSI设备,
/dev/tape 和 /dev/cdrom 应该分别指向"cooked"设备 /dev/st* 和 /dev/sr* ;
而 /dev/cdwriter 和 /dev/scanner 应当分别指向恰当的 /dev/sg* 。
/dev/mouse 可以指向一个主串行 TTY 设备、一个硬件鼠标、
或者一个对应鼠标驱动程序的套接字(例如 /dev/gpmdata)。
套接字和管道
持久套接字和命名管道可以存在于 /dev 中。常见的有:
/dev/printer socket lpd 本地套接字
/dev/log socket syslog 本地套接字
/dev/gpmdata socket gpm 鼠标多路复用器(multiplexer)
/dev/gpmctl socket (LFS-LiveCD中出现)
/dev/initctl fifo pipe init 监听它并从中获取信息(用户与 init 进程交互的通道)
挂载点
以下名称被保留用于挂载特殊的文件系统。
这些特殊的文件系统只提供内核界面而不提供标准的设备节点。
/dev/pts devpts PTY slave 文件系统
/dev/shm tmpfs 提供对 POSIX 共享内存的直接访问
===================================================================
终端(或TTY)设备是一种特殊的字符设备。终端设备是可以在会话中扮演控制终端角色的任何设备,
包括:虚拟控制台、串行接口(已废弃)、伪终端(PTY)。
所有的终端设备共享一个通用的功能集合:line discipline,
它既包含通用的终端 line discipline 也包含SLIP和PPP模式。
所有的终端设备的命名都很相似。这部分内容将解释命名规则和各种类型的TTY(终端)的使用。
需要注意的是这些命名习惯包含了几个历史遗留包袱。
其中的一些是Linux所特有的,另一些则是继承自其他系统,
还有一些反映了Linux在成长过程中抛弃了原来借用自其它系统的一些习惯。
井号(#)在设备名里表示一个无前导零的十进制数。
虚拟控制台(Virtual console)和控制台设备(console device)
虚拟控制台是在系统视频监视器上全屏显示的终端。
虚拟控制台被命名为编号从 /dev/tty1 开始的 /dev/tty# 。
/dev/tty0 是当前虚拟控制台。
/dev/tty0 用于在不能使用帧缓冲设备(/dev/fb*)的机器上存取系统视频卡,
注意,不要将 /dev/console 用于此目的。
/dev/console 由内核管理,系统消息将被发送到这里。
单用户模式下必须允许 login 使用 /dev/console 。
串行接口(已废弃)
这里所说的"串行接口"是指 RS-232 串行接口和任何模拟这种接口的设备,
不管是在硬件(例如调制解调器)还是在软件(例如ISDN驱动)中模拟。
在linux中的每一个串行接口都有两个设备名:
主设备或呼入(callin)设备、交替设备或呼出(callout)设备。
设备类型之间使用字母的大小写进行区分。
比如,对于任意字母X,"tty"设备名为 /dev/ttyX# ,而"cu"设备名则为 /dev/cux# 。
由于历史原因,/dev/ttyS# 和 /dev/ttyC# 分别等价于 /dev/cua# 和 /dev/cub# 。
名称 /dev/ttyQ# 和 /dev/cuq# 被保留为本地使用。
伪终端(PTY)
伪终端用于创建登陆会话或提供其它功能,
比如通过 TTY line discipline (包括SLIP或者PPP功能)来处理任意的数据生成。
每一个 PTY 都有一个master端和一个slave端。按照 System V/Unix98 的 PTY 命名方案,
所有master端共享同一个 /dev/ptmx 设备节点(打开它内核将自动给出一个未分配的PTY),
所有slave端都位于 /dev/pts 目录下,名为 /dev/pts/# (内核会根据需要自动生成和删除它们)。
一旦master端被打开,相应的slave设备就可以按照与 TTY 设备完全相同的方式使用。
master设备与slave设备之间通过内核进行连接,等价于拥有 TTY 功能的双向管道(pipe)。
===============================
你可能会很奇怪,为什么没有 /dev/hda 这样的设备,难道不常用么?
原因在于从 2.6.19 开始,内核引入了新的ATA驱动,将SATA/IDE硬盘同意使用 /dev/sd? 来表示了,所以 /dev/hd? 就没有存在的必要了
sed 编辑器是 Linux 系统管理员的工具包中最有用的资产之一Linux *** 作系统最大的一个好处是它带有各种各样的实用工具。存在如此之多不同的实用工具,几乎不可能知道并了解所有这些工具。可以简化关键情况下 *** 作的一个实用 工具是 sed。它是任何管理员的工具包中最强大的工具之一,并且可以证明它自己在关键情况下非常有价值。
sed 实用工具是一个“编辑器”,但它与其它大多数编辑器不同。除了不面向屏幕之外,它还是非交互式的。这意味着您必须将要对数据执行的命令插入到命令行或要处 理的脚本中。当显示它时,请忘记您在使用 Microsoft Word 或其它大多数编辑器时拥有的交互式编辑文件功能。sed 在一个文件(或文件集)中非交互式、并且不加询问地接收一系列的命令并执行它们。因而,它流经文本就如同水流经溪流一样,因而 sed 恰当地代表了流编辑器。它可以用来将所有出现的 "Mr. Smyth" 修改为 "Mr. Smith",或将 "tiger cub" 修改为 "wolf cub"。流编辑器非常适合于执行重复的编辑,这种重复编辑如果由人工完成将花费大量的时间。其参数可能和一次性使用一个简单的 *** 作所需的参数一样有限, 或者和一个具有成千上万行要进行编辑修改的脚本文件一样复杂。sed 是 Linux 和 UNIX 工具箱中最有用的工具之一,且使用的参数非常少。
sed 的工作方式
sed 实用工具按顺序逐行将文件读入到内存中。然后,它执行为该行指定的所有 *** 作,并在完成请求的修改之后将该行放回到内存中,以将其转储至终端。完成了这一行 上的所有 *** 作之后,它读取文件的下一行,然后重复该过程直到它完成该文件。如同前面所提到的,默认输出是将每一行的内容输出到屏幕上。在这里,开始涉及到 两个重要的因素—首先,输出可以被重定向到另一文件中,以保存变化;第二,源文件(默认地)保持不被修改。sed 默认读取整个文件并对其中的每一行进行修改。不过,可以按需要将 *** 作限制在指定的行上。
该实用工具的语法为:
sed [options] '{command}' [filename]
在这篇文章中,我们将浏览最常用的命令和选项,并演示它们如何工作,以及它们适于在何处使用。
替换命令
sed 实用工具以及其它任何类似的编辑器的最常用的命令之一是用一个值替换另一个值。用来实现这一目的的 *** 作的命令部分语法是:
's/{old value}/{new value}/'
因而,下面演示了如何非常简单地将 "tiger" 修改为 "wolf":
$ echo The tiger cubs will meet on Tuesday after school | sed
's/tiger/wolf/'
The wolf cubs will meet on Tuesday after school
$
注意如果输入是源自之前的命令输出,则不需要指定文件名—同样的原则也适用于 awk、sort 和其它大多数 LinuxUNIX 命令行实用工具程序。
多次修改
如果需要对同一文件或行作多次修改,可以有三种方法来实现它。第一种是使用 "-e" 选项,它通知程序使用了多条编辑命令。例如:
$ echo The tiger cubs will meet on Tuesday after school | sed -e '
s/tiger/wolf/' -e 's/after/before/'
The wolf cubs will meet on Tuesday before school
$
这是实现它的非常复杂的方法,因此 "-e" 选项不常被大范围使用。更好的方法是用分号来分隔命令:
$ echo The tiger cubs will meet on Tuesday after school | sed '
s/tiger/wolf/s/after/before/'
The wolf cubs will meet on Tuesday before school
$
注 意分号必须是紧跟斜线之后的下一个字符。如果两者之间有一个空格, *** 作将不能成功完成,并返回一条错误消息。这两种方法都很好,但许多管理员更喜欢另一种 方法。要注意的一个关键问题是,两个撇号 (' ') 之间的全部内容都被解释为 sed 命令。直到您输入了第二个撇号,读入这些命令的 shell 程序才会认为您完成了输入。这意味着可以在多行上输入命令—同时 Linux 将提示符从 PS1 变为一个延续提示符(通常为 ">")—直到输入了第二个撇号。一旦输入了第二个撇号,并且按下了 Enter 键,则处理就进行并产生相同的结果,如下所示:
$ echo The tiger cubs will meet on Tuesday after school | sed '
>s/tiger/wolf/
>s/after/before/'
The wolf cubs will meet on Tuesday before school
$
全局修改
让我们开始一次看似简单的编辑。假定在要修改的消息中出现了多次要修改的项目。默认方式下,结果可能和预期的有所不同,如下所示:
$ echo The tiger cubs will meet this Tuesday at the same time
as the meeting last Tuesday | sed 's/Tuesday/Thursday/'
The tiger cubs will meet this Thursday at the same time
as the meeting last Tuesday
$
与 将出现的每个 "Tuesday" 修改为 "Thursday" 相反,sed 编辑器在找到一个要修改的项目并作了修改之后继续处理下一行,而不读整行。sed 命令功能大体上类似于替换命令,这意味着它们都处理每一行中出现的第一个选定序列。为了替换出现的每一个项目,在同一行中出现多个要替换的项目的情况下, 您必须指定在全局进行该 *** 作:
$ echo The tiger cubs will meet this Tuesday at the same time
as the meeting last Tuesday | sed 's/Tuesday/Thursday/g'
The tiger cubs will meet this Thursday at the same time
as the meeting last Thursday
$
请记住不管您要查找的序列是否仅包含一个字符或词组,这种对全局化的要求都是必需的。
sed 还可以用来修改记录字段分隔符。例如,以下命令将把所有的 tab 修改为空格:
sed 's// /g'
其 中,第一组斜线之间的项目是一个 tab,而第二组斜线之间的项目是一个空格。作为一条通用的规则,sed 可以用来将任意的可打印字符修改为任意其它的可打印字符。如果您想将不可打印字符修改为可打印字符—例如,铃铛修改为单词 "bell"—sed 不是适于完成这项工作的工具(但 tr 是)。
有时,您不想修改在一个文件中出现的所有指定项目。有时,您只想在满足某些条件时才作修改—例如,在与其它一些数据匹配之后才作修改。为了说明这一点,请考虑以下文本文件:
$ cat sample_one
one 1
two 1
three 1
one 1
two 1
two 1
three 1
$
假定希望用 "2" 来替换 "1",但仅在单词 "two" 之后才作替换,而不是每一行的所有位置。通过指定在给出替换命令之前必须存在一次匹配,可以实现这一点:
$ sed '/two/ s/1/2/' sample_one
one 1
two 2
three 1
one 1
two 2
two 2
three 1
$
现在,使其更加准确:
$ sed '
>/two/ s/1/2/
>/three/ s/1/3/' sample_one
one 1
two 2
three 3
one 1
two 2
two 2
three 3
$
请 再次记住唯一改变了的是显示。如果您查看源文件,您将发现它始终保持不变。您必须将输出保存至另一个文件,以实现永久保存。值得重复的是,不对源文件作修 改实际是祸中有福—它让您能够对文件进行试验而不会造成任何实际的损害,直到让正确命令以您预期和希望的方式进行工作。
以下命令将修改后的输出保存至一个新的文件:
$ sed '
>/two/ s/1/2/
>/three/ s/1/3/' sample_one >sample_two
该输出文件将所有修改合并在其中,并且这些修改通常将在屏幕上显示。现在可以用 head、cat 或任意其它类似的实用工具来进行查看。
脚本文件
sed 工具允许您创建一个脚本文件,其中包含从该文件而不是在命令行进行处理的命令,并且 sed 工具通过 "-f" 选项来引用。通过创建一个脚本文件,您能够一次又一次地重复运行相同的 *** 作,并指定比每次希望从命令行进行处理的 *** 作详细得多的 *** 作。
考虑以下脚本文件:
$ cat sedlist
/two/ s/1/2/
/three/ s/1/3/
$
现在可以在数据文件上使用脚本文件,获得和我们之前看到的相同的结果:
$ sed -f sedlist sample_one
one 1
two 2
three 3
one 1
two 2
two 2
three 3
$
注意当调用 "-f" 选项时,在源文件内或命令行中不使用撇号。脚本文件,也称为源文件,对于想重复多次的 *** 作和从命令行运行可能出错的复杂命令很有价值。编辑源文件并修改一个字符比在命令行中重新输入一条多行的项目要容易得多。
限制行
编辑器默认查看输入到流编辑器中的每一行,且默认在输入到流编辑器中的每一行上进行编辑。这可以通过在发出命令之前指定约束条件来进行修改。例如,只在此示例文件的输出的第 5 和第 6 行中用 "2" 来替换 "1",命令将为:
$ sed '5,6 s/1/2/' sample_one
one 1
two 1
three 1
one 1
two 2
two 2
three 1
$
在这种情况下,因为要修改的行是专门指定的,所以不需要替换命令。因此,您可以灵活地根据匹配准则(可以是行号或一种匹配模式)来选择要修改哪些行(从根本上限制修改)。
禁止显示
sed 默认将来自源文件的每一行显示到屏幕上(或重定向到一个文件中),而无论该行是否受到编辑 *** 作的影响,"-n" 参数覆盖了这一 *** 作。"-n" 覆盖了所有的显示,并且不显示任何一行,而无论它们是否被编辑 *** 作修改。例如:
$ sed -n -f sedlist sample_one
$
$ sed -n -f sedlist sample_one >sample_two
$ cat sample_two
$
在 第一个示例中,屏幕上不显示任何东西。在第二个示例中,不修改任何东西,因此不将任何东西写到新的文件中—它最后是空的。这不是否定了编辑的全部目的吗? 为什么这是有用的?它是有用的仅因为 "-n" 选项能够被一条显示命令 (-p) 覆盖。为了说明这一点,假定现在像下面这样对脚本文件进行了修改:
$ cat sedlist
/two/ s/1/2/p
/three/ s/1/3/p
$
然后下面是运行它的结果:
$ sed -n -f sedlist sample_one
two 2
three 3
two 2
two 2
three 3
$
保持不变的行全部不被显示。只有受到编辑 *** 作影响的行被显示了。在这种方式下,可以仅取出这些行,进行修改,然后把它们放到一个单独的文件中:
$ sed -n -f sedlist sample_one >sample_two
$
$ cat sample_two
two 2
three 3
two 2
two 2
three 3
$
利用它的另一种方法是只显示一定数量的行。例如,只显示 2-6 行,同时不做其它的编辑修改:
$ sed -n '2,6p' sample_one
two 1
three 1
one 1
two 1
two 1
$
其它所有的行被忽略,只有 2-6 行作为输出显示。这是一项出色的功能,其它任何工具都不能容易地实现。Head 将显示一个文件的顶部,而 tail 将显示一个文件的底部,但 sed 允许从任意位置取出想要的任意内容。
删除行
用一个值替换另一个值远非流编辑器可以执行的唯一功能。它还具有许多的潜在功能,在我看来第二种最常用的功能是删除。删除与替换的工作方式相同,只是它删除指定的行(如果您想要删除一个单词而不是一行,不要考虑删除,而应考虑用空的内容来替换它—s/cat//)。
该命令的语法是:
'{what to find} d'
从 sample_one 文件中删除包含 "two" 的所有行:
$ sed '/two/ d' sample_one
one 1
three 1
one 1
three 1
$
从显示屏中删除前三行,而不管它们的内容是什么:
$ sed '1,3 d' sample_one
one 1
two 1
two 1
three 1
$
只显示剩下的行,前三行不在显示屏中出现。对于流编辑器,一般当它们涉及到全局表达式时,特别是应用于删除 *** 作时,有几点要记住:
上三角号 (^) 表示一行的开始,因此,如果 "two" 是该行的头三个字符,则
sed '/^two/ d' sample_one
将只删除该行。
美元符号 ($) 代表文件的结尾,或一行的结尾,因此,如果 "two" 是该行的最后三个字符,则
sed '/two$/ d' sample_one
将只删除该行。
将这两者结合在一起的结果:
sed '/^$/ d' {filename}
删除文件中的所有空白行。例如,以下命令将 "1" 替换为 "2",以及将 "1" 替换为 "3",并删除文件中所有尾随的空行:
$ sed '/two/ s/1/2//three/ s/1/3//^$/ d' sample_one
one 1
two 1
three 1
one 1
two 2
two 2
three 1
$
其通常的用途是删除一个标题。以下命令将删除文件中所有的行,从第一行直到第一个空行:
sed '1,/^$/ d' {filename}
添加和插入文本
可以结合使用 sed 和 "a" 选项将文本添加到一个文件的末尾。实现方法如下:
$ sed '$a
>This is where we stop
>the test' sample_one
one 1
two 1
three 1
one 1
two 1
two 1
three 1
This is where we stop
the test
$
在该命令中,美元符号 ($) 表示文本将被添加到文件的末尾。反斜线 () 是必需的,它表示将插入一个回车符。如果它们被遗漏了,则将导致一个错误,显示该命令是错乱的;在任何要输入回车的地方您必须使用反斜线。
要将这些行添加到第 4 和第 5 个位置而不是末尾,则命令变为:
$ sed '3a
>This is where we stop
>the test' sample_one
one 1
two 1
three 1
This is where we stop
the test
one 1
two 1
two 1
three 1
$
这将文本添加到第 3 行之后。和几乎所有的编辑器一样,您可以选择插入而不是添加(如果您希望这样的话)。这两者的区别是添加跟在指定的行之后,而插入从指定的行开始。当用插入来代替添加时,只需用 "i" 来代替 "a",如下所示:
$ sed '3i
>This is where we stop
>the test' sample_one
one 1
two 1
This is where we stop
the test
three 1
one 1
two 1
two 1
three 1
$
新的文本出现在输出的中间位置,而处理通常在指定的 *** 作执行以后继续进行。
读写文件
重定向输出的功能已经演示过了,但需要指出的是,在编辑命令运行期间可以同步地读入和写出文件。例如,执行替换,并将 1-3 行写到名称为 sample_three 的文件中:
$ sed '
>/two/ s/1/2/
>/three/ s/1/3/
>1,3 w sample_three' sample_one
one 1
two 2
three 3
one 1
two 2
two 2
three 3
$
$ cat sample_three
one 1
two 2
three 3
$
由于为 w (write) 命令指定了 "1,3",所以只有指定的行被写到了新文件中。无论被写的是哪些行,所有的行都在默认输出中显示。
修改命令
除了替换项目之外,还可以将行从一个值修改为另一个值。要记住的是,替换是对字符逐个进行,而修改功能与删除类似,它影响整行:
$ sed '/two/ c
>We are no longer using two' sample_one
one 1
We are no longer using two
three 1
one 1
We are no longer using two
We are no longer using two
three 1
$
修 改命令与替换的工作方式很相似,但在范围上要更大些—将一个项目完全替换为另一个项目,而无论字符内容或上下文。夸张一点讲,当使用替换时,只有字符 "1" 被字符 "2" 替换,而当使用修改时,原来的整行将被修改。在两种情况下,要寻找的匹配条件都仅为 "two"。
修改全部但……
对于大多数 sed 命令,详细说明各种功能要进行何种修改。利用感叹号,可以在除指定位置之外的任何地方执行修改—与默认的 *** 作完全相反。
例如,要删除包含单词 "two" 的所有行, *** 作为:
$ sed '/two/ d' sample_one
one 1
three 1
one 1
three 1
$
而要删除除包含单词 "two" 的行之外的所有行,则语法变为:
$ sed '/two/ !d' sample_one
two 1
two 1
two 1
$
如果您有一个文件包含一系列项目,并且想对文件中的每个项目执行一个 *** 作,那么首先对那些项目进行一次智能扫描并考虑将要做什么是很重要的。为了使事情变得更简单,您可以将 sed 与任意迭代例程(for、while、until)结合来实现这一目的。
比如说,假定您有一个名为 "animals" 的文件,其中包含以下项目:
pig
horse
elephant
cow
dog
cat
您希望运行以下例程:
#mcd.ksh
for I in $*
do
echo Old McDonald had a $I
echo E-I, E-I-O
done
结 果将为,每一行都显示在 "Old McDonald has a" 的末尾。虽然对于这些项目的大部分这是正确的,但对于 "elephant" 项目,它有语法错误,因为结果应当为 "an elephant" 而不是 "a elephant"。利用 sed,您可以在来自 shell 文件的输出中检查这种语法错误,并通过首先创建一个命令文件来即时地更正它们:
#sublist
/ a a/ s/ a / an /
/ a e/ s/ a / an /
/a i/ s / a / an /
/a o/ s/ a / an /
/a u/ s/ a / an /
然后执行以下过程:
$ sh mcd.ksh 'cat animals' | sed -f sublist
现 在,在运行了 mcd 脚本之后,sed 将在输出中搜索单个字母 a (空格,"a",空格)之后紧跟了一个元音的任意位置。如果这种位置存在,它将把该序列修改为空格,"an",空格。这样就使问题更正后才显示在屏幕上, 并确保各处的编辑人员在晚上可以更容易地入睡。结果是:
Old McDonald had a pig
E-I, E-I-O
Old McDonald had a horse
E-I, E-I-O
Old McDonald had an elephant
E-I, E-I-O
Old McDonald had a cow
E-I, E-I-O
Old McDonald had a dog
E-I, E-I-O
Old McDonald had a cat
E-I, E-I-O
提前退出
sed 默认读取整个文件,并只在到达末尾时才停止。不过,您可以使用退出命令提前停止处理。只能指定一条退出命令,而处理将一直持续直到满足调用退出命令的条件。
例如,仅在文件的前五行上执行替换,然后退出:
$ sed '
>/two/ s/1/2/
>/three/ s/1/3/
>5q' sample_one
one 1
two 2
three 3
one 1
two 2
$
在退出命令之前的项目可以是一个行号(如上所示),或者一条查找/匹配命令:
$ sed '
>/two/ s/1/2/
>/three/ s/1/3/
>/three/q' sample_one
one 1
two 2
three 3
$
您 还可以使用退出命令来查看超过一定标准数目的行,并增加比 head 中的功能更强的功能。例如,head 命令允许您指定您想要查看一个文件的前多少行—默认数为 10,但可以使用从 1 到 99 的任意一个数字。如果您想查看一个文件的前 110 行,您用 head 不能实现这一目的,但用 sed 可以:
sed 110q filename
处理问题
当使用 sed 时,要记住的重要事项是它的工作方式。它的工作方式是:读入一行,在该行上执行它已知要执行的所有任务,然后继续处理下一行。每一行都受给定的每一个编辑命令的影响。
如果您的 *** 作顺序没有十分彻底地考虑清楚,那么这可能会很麻烦。例如,假定您需要将所有的 "two" 项目修改为 "three",然后将所有的 "three" 修改为 "four":
$ sed '
>/two/ s/two/three/
>/three/ s/three/four/' sample_one
one 1
four 1
four 1
one 1
four 1
four 1
four 1
$
最初读取的 "two" 被修改为 "three"。然后它满足为下一次编辑建立的准则,从而变为 "four"。最终的结果不是想要的结果—现在除了 "four" 没有别的项目了,而本来应该有 "three" 和 "four"。
当执行这种 *** 作时,您必须非常用心地注意指定 *** 作的方式,并按某种顺序来安排它们,使得 *** 作之间不会互相影响。例如:
$ sed '
>/three/ s/three/four/
>/two/ s/two/three/' sample_one
one 1
three 1
four 1
one 1
three 1
three 1
four 1
$
这非常有效,因为 "three" 值在 "two" 变成 "three" 之前得到修改。
标签和注释
可以在 sed 脚本文件中放置标签,这样一旦文件变得庞大,可以更容易地说明正在发生的事情。存在各种各样与这些标签相关的命令,它们包括:
接下来的步骤
访问并收藏 Linux 技术中心
阅读 Dale Dougherty 和 Arnold Robbins 的著作 sed &awk, 2nd Edition (O'Reilly &Associates 出版社)。
: 冒号表示一个标签名称。例如:
:HERE
以冒号开始的标签可以由 "b" 和 "t" 命令处理。
b
充当 "goto" 语句的作用,将处理发送至前面有一个冒号的标签。例如, b HERE 将处理发送给行 :HERE 如果紧跟 b 之后没有指定任何标签,则处理转至脚本文件的末尾。 t只要自上次输入行或执行一次 "t" 命令以来进行了替换 *** 作,就转至该标签。和 "b" 一样,如果没有给定标签名,则处理转至脚本文件的末尾。
# 符号作为一行的第一个字符将使整行被当作注释处理。注释行与标签不同,不能使用 b 或 t 命令来转到注释行上。首先我这边先建一个字母大小转换的脚本test2.sh,内容如下:先介绍些sed -n的应用:sed命令中p能实现打印匹配行的功能。我们可以实际看下sed命令带-n和不带-n情况下有什么不同。sed -n "1p" test2.sh:带-n选项的话,只打印test2.sh脚本第一行匹配行。sed "1p" test2.sh:不带-n的话,不仅打印第一行匹配行,还打印输出test2.sh脚本的全部内容。sed -n还可以打印文件的范围,比如打印test2.sh脚本的前两行,我们就可以执行以下命令:sed -n "1,2p" test2.sh,就可以直接打印前两行。sed命令可以打印匹配模式行,比如打印test2.sh脚本匹配tr的行,就可以执行以下命令:sed -n /tr/p test2.sh。remark:如果不带-n的话,除了打印匹配行外,还会打印脚本的全部内容。sed -e的应用。只有当sed命令传递多个编辑命令式,才会使用到-e。比如:我想打印/tr/匹配行,并且打印匹配行所在的行号,此时存在多个sed参数,就要用到-e了。sed -n -e /tr/p -e /tr/= test2.sh每个参数前都要带上-e:sed a\追加命令,命令格式为:sed ’指定地址a\追加内容‘ 目标文件这个追加内容在匹配行的下一行,只会输出到标准输出,原文件内容是不变的,例如在test2.sh脚本的/tr/所在的匹配行的下一行添加“#hello”内容,可需要执行:sed '/tr/a\#hello' test2.sh一定不要忘记单引号.还有一个sed i\的追加命令,命令格式为:sed ’指定地址i\追加内容‘ 目标文件,跟a\不同,i\追加是在指定位置的上一行追加命令sed命令中还有一些特殊的匹配,比如元字符匹配,此时需要用转义符"\"屏蔽其特殊意义。比如:sed -n ‘/\=/p’test2.sh,则打印输出tr一行。$在正则表达式中表示尾行,执行sed -n ‘$p’ test2.sh则打印脚本尾行。!表示取反,可以看以下两个例子sed中可以使用关键字来匹配行,打印我们所需要的内容,比如,我希望打印test2.sh第2,3行,可以执行:sed -n "2,3P" test2.sh,也可以执行sed -n "/tr/,/exit/p" test2.shsed c\的应用,命令格式为:sed ’指定地址c\替换内容‘ 目标文件。比如,#hello,替换test2.sh脚本的tr这行,可以执行命令:sed '/tr/c\#hello' test2.shsed删除d应用:比如我想删除test2.sh的第2行,可以执行以下命令:sed "2d" test2.sh或者sed /tr/d test2.shsed替换s应用:格式 sed s/被替换的字符/替换字符/[替换选项]比如,我想把test2.sh中tr替换成大写的tr,则可以执行以下命令:sed ‘s/tr/TR/’test2.sh,则把脚本中的tr替换成TR,完后输出全部内容。如果仅想打印替换所在行,则需要试用使用-n和-p:sed -n ‘s/tr/TR/p’ test2.sh:把脚本中的tr替换成TR,然后打印tr所在的行.如果脚本中存在好几个tr,并且每一行也存在多个tr,如果执行以上命令的话,只会更改每一行的第一个出现的tr,如果要全部把tr转后为TR,则需要添加G参数:sed -n ’S/tr/TR/pg’test2.sh。w参数是定向输入参数,比如要把上述的变更定向输出到test1.txt中,则需要执行:sed -n ’s/tr/TR/pgw test1.txt’ test2.sh。也可以直接把选定的匹配内容写到另一个文本中,比如想把test2.sh中tr这一样写到test2.txt中,执行:sed -n ’/tr/w test2.txt‘ test2.sh


评论列表(0条)