目录/dev目录包含了 物理设备 的条目,这些设备可能存在于硬件中,也可能不存在。[1] 顾名思义,这些被称为 设备文件。例如,包含已挂载文件系统的硬盘分区在以下目录中有条目:/dev,正如 df 命令显示的那样。
bash$ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda6 495876 222748 247527 48% / /dev/hda1 50755 3887 44248 9% /boot /dev/hda8 367013 13262 334803 4% /home /dev/hda5 1714416 1123624 503704 70% /usr |
除此之外,/dev目录还包含 环回 设备,例如/dev/loop0。环回设备是一种技巧,允许像访问块设备一样访问普通文件。[2] 这允许在单个大文件中挂载整个文件系统。请参阅 示例 17-8 和 示例 17-7。
中的一些伪设备/dev还有其他专门用途,例如 /dev/null、/dev/zero、/dev/urandom、/dev/sda1(硬盘分区),/dev/udp(用户数据报协议 端口),以及 /dev/tcp。
例如
要手动 挂载 USB 闪存驱动器,请将以下行附加到 /etc/fstab。[3]
/dev/sda1 /mnt/flashdrive auto noauto,user,noatime 0 0 |
检查光盘是否在 CD 刻录机中(软链接到/dev/hdc):
head -1 /dev/hdc # head: cannot open '/dev/hdc' for reading: No medium found # (No disc in the drive.) # head: error reading '/dev/hdc': Input/output error # (There is a disk in the drive, but it can't be read; #+ possibly it's an unrecorded CDR blank.) # Stream of characters and assorted gibberish # (There is a pre-recorded disk in the drive, #+ and this is raw output -- a stream of ASCII and binary data.) # Here we see the wisdom of using 'head' to limit the output #+ to manageable proportions, rather than 'cat' or something similar. # Now, it's just a matter of checking/parsing the output and taking #+ appropriate action. |
当在/dev/tcp/$host/$port伪设备文件上执行命令时,Bash 会打开一个到关联 套接字 的 TCP 连接。
从nist.gov:
bash$ cat </dev/tcp/time.nist.gov/13 53082 04-03-18 04:26:54 68 0 0 502.3 UTC(NIST) * |
[Mark 贡献了这个示例。]
将上述内容概括为一个脚本
#!/bin/bash
# This script must run with root permissions.
URL="time.nist.gov/13"
Time=$(cat </dev/tcp/"$URL")
UTC=$(echo "$Time" | awk '{print$3}') # Third field is UTC (GMT) time.
# Exercise: modify this for different time zones.
echo "UTC Time = "$UTC"" |
bash$ exec 5<>/dev/tcp/www.net.cn/80 bash$ echo -e "GET / HTTP/1.0\n" >&5 bash$ cat <&5 |
[感谢 Mark 和 Mihai Maties。]
示例 29-1. 使用/dev/tcp用于故障排除
#!/bin/bash
# dev-tcp.sh: /dev/tcp redirection to check Internet connection.
# Script by Troy Engel.
# Used with permission.
TCP_HOST=news-15.net # A known spam-friendly ISP.
TCP_PORT=80 # Port 80 is http.
# Try to connect. (Somewhat similar to a 'ping' . . .)
echo "HEAD / HTTP/1.0" >/dev/tcp/${TCP_HOST}/${TCP_PORT}
MYEXIT=$?
: <<EXPLANATION
If bash was compiled with --enable-net-redirections, it has the capability of
using a special character device for both TCP and UDP redirections. These
redirections are used identically as STDIN/STDOUT/STDERR. The device entries
are 30,36 for /dev/tcp:
mknod /dev/tcp c 30 36
>From the bash reference:
/dev/tcp/host/port
If host is a valid hostname or Internet address, and port is an integer
port number or service name, Bash attempts to open a TCP connection to the
corresponding socket.
EXPLANATION
if [ "X$MYEXIT" = "X0" ]; then
echo "Connection successful. Exit code: $MYEXIT"
else
echo "Connection unsuccessful. Exit code: $MYEXIT"
fi
exit $MYEXIT |
示例 29-2. 播放音乐
#!/bin/bash
# music.sh
# Music without external files
# Author: Antonio Macchi
# Used in ABS Guide with permission.
# /dev/dsp default = 8000 frames per second, 8 bits per frame (1 byte),
#+ 1 channel (mono)
duration=2000 # If 8000 bytes = 1 second, then 2000 = 1/4 second.
volume=$'\xc0' # Max volume = \xff (or \x00).
mute=$'\x80' # No volume = \x80 (the middle).
function mknote () # $1=Note Hz in bytes (e.g. A = 440Hz ::
{ #+ 8000 fps / 440 = 16 :: A = 16 bytes per second)
for t in `seq 0 $duration`
do
test $(( $t % $1 )) = 0 && echo -n $volume || echo -n $mute
done
}
e=`mknote 49`
g=`mknote 41`
a=`mknote 36`
b=`mknote 32`
c=`mknote 30`
cis=`mknote 29`
d=`mknote 27`
e2=`mknote 24`
n=`mknote 32767`
# European notation.
echo -n "$g$e2$d$c$d$c$a$g$n$g$e$n$g$e2$d$c$c$b$c$cis$n$cis$d \
$n$g$e2$d$c$d$c$a$g$n$g$e$n$g$a$d$c$b$a$b$c" > /dev/dsp
# dsp = Digital Signal Processor
exit # A "bonny" example of an elegant shell script! |
| [1] | 中的条目/dev为物理和虚拟设备提供挂载点。这些条目占用非常少的驱动器空间。 一些设备,例如/dev/null, /dev/zero,以及/dev/urandom是虚拟的。它们不是实际的物理设备,仅存在于软件中。 |
| [2] | 块设备 以块或 数据块 为单位读取和/或写入数据,这与 字符设备 形成对比,后者以 字符 单位访问数据。块设备的示例包括硬盘驱动器、CD-ROM 驱动器和闪存驱动器。字符设备的示例包括键盘、调制解调器、声卡。 |
| [3] | 当然,挂载点/mnt/flashdrive必须存在。如果不存在,则以 root 身份,执行 mkdir /mnt/flashdrive。 要实际挂载驱动器,请使用以下命令:mount /mnt/flashdrive 较新的 Linux 发行版自动挂载闪存驱动器到/media目录中,无需用户干预。 |