📄 zeros.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><HTML><HEAD><TITLE>Zero与Null</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINKREL="HOME"TITLE="高级Bash脚本编程指南"HREF="index.html"><LINKREL="UP"TITLE="高级主题"HREF="part4.html"><LINKREL="PREVIOUS"TITLE="/proc"HREF="procref1.html"><LINKREL="NEXT"TITLE="调试"HREF="debugging.html"></HEAD><BODYCLASS="CHAPTER"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="procref1.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="debugging.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="ZEROS"></A>28. Zero与Null</H1><P><ANAME="ZEROSREF"></A></P><P></P><DIVCLASS="VARIABLELIST"><P><B><ANAME="ZERONULL1"></A><TTCLASS="FILENAME">/dev/zero</TT>与<TTCLASS="FILENAME">/dev/null</TT></B></P><DL><DT>使用<TTCLASS="FILENAME">/dev/null</TT></DT><DD><P>可以把<TTCLASS="FILENAME">/dev/null</TT>想象为一个<SPANCLASS="QUOTE">"黑洞"</SPAN>. 它非常接近于一个只写文件. 所有写入它的内容都会永远丢失. 而如果想从它那读取内容, 则什么也读不到. 但是, 对于命令行和脚本来说, <TTCLASS="FILENAME">/dev/null</TT>却非常的有用. </P><P>禁用<TTCLASS="FILENAME">stdout</TT>. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 cat $filename >/dev/null 2 # 文件的内容不会输出到stdout. </PRE></FONT></TD></TR></TABLE> </P><P>禁用<TTCLASS="FILENAME">stderr</TT> (来自于<AHREF="moreadv.html#EX57">例子 12-3</A>). <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 rm $badname 2>/dev/null 2 # 错误消息[stderr]就这么被丢到太平洋去了. </PRE></FONT></TD></TR></TABLE> </P><P>禁用<TTCLASS="FILENAME">stdout</TT>和<TTCLASS="FILENAME">stderr</TT>. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 cat $filename 2>/dev/null >/dev/null 2 # 如果"$filename"不存在, 将不会有错误消息输出. 3 # 如果"$filename"存在, 文件内容不会输出到stdout. 4 # 因此, 上边的代码根本不会产生任何输出. 5 # 6 # 如果你只想测试一下命令的返回码, 而不想要任何输出时, 7 #+ 这么做就非常有用了. 8 # 9 # cat $filename &>/dev/null 10 # 也可以, 由Baris Cicek指出. </PRE></FONT></TD></TR></TABLE> </P><P>删除一个文件的内容, 但是保留文件本身, 并且保留所有的文件访问权限(来自于<AHREF="sha-bang.html#EX1">例子 2-1</A>和<AHREF="sha-bang.html#EX2">例子 2-3</A>): <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 cat /dev/null > /var/log/messages 2 # : > /var/log/messages 具有同样的效果, 但是不会产生新进程.(译者注: 因为是内建的) 3 4 cat /dev/null > /var/log/wtmp</PRE></FONT></TD></TR></TABLE> </P><P>自动清空日志文件的内容(特别适用于处理那些由商业站点发送的, 令人厌恶的<SPANCLASS="QUOTE">"cookie"</SPAN>):</P><DIVCLASS="EXAMPLE"><HR><ANAME="COOKIES"></A><P><B>例子 28-1. 隐藏令人厌恶的cookie</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 if [ -f ~/.netscape/cookies ] # 如果存在, 就删除. 2 then 3 rm -f ~/.netscape/cookies 4 fi 5 6 ln -s /dev/null ~/.netscape/cookies 7 # 现在所有的cookie都被扔到黑洞里去了, 这样就不会保存在我们的磁盘中了. </PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="ZEROSREF1"></A>使用<TTCLASS="FILENAME">/dev/zero</TT></DT><DD><P>类似于<TTCLASS="FILENAME">/dev/null</TT>, <TTCLASS="FILENAME">/dev/zero</TT>也是一个伪文件, 但事实上它会产生一个null流(二进制的0流, 而不是ASCII类型). 如果你想把其他命令的输出写入它的话, 那么写入的内容会消失, 而且如果你想从<TTCLASS="FILENAME">/dev/zero</TT>中读取一连串null的话, 也非常的困难, 虽然可以使用<AHREF="extmisc.html#ODREF">od</A>或者一个16进制编辑器来达到这个目的. <TTCLASS="FILENAME">/dev/zero</TT>的主要用途就是用来创建一个指定长度, 并且初始化为空的文件, 这种文件一般都用作临时交换文件. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX73"></A><P><B>例子 28-2. 使用<TTCLASS="FILENAME">/dev/zero</TT>来建立一个交换文件</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 创建一个交换文件. 3 4 ROOT_UID=0 # Root用户的$UID为0. 5 E_WRONG_USER=65 # 不是root? 6 7 FILE=/swap 8 BLOCKSIZE=1024 9 MINBLOCKS=40 10 SUCCESS=0 11 12 13 # 这个脚本必须以root身份来运行. 14 if [ "$UID" -ne "$ROOT_UID" ] 15 then 16 echo; echo "You must be root to run this script."; echo 17 exit $E_WRONG_USER 18 fi 19 20 21 blocks=${1:-$MINBLOCKS} # 如果没在命令行上指定, 22 #+ 默认设置为40块. 23 # 上边这句等价于下面这个命令块. 24 # -------------------------------------------------- 25 # if [ -n "$1" ] 26 # then 27 # blocks=$1 28 # else 29 # blocks=$MINBLOCKS 30 # fi 31 # -------------------------------------------------- 32 33 34 if [ "$blocks" -lt $MINBLOCKS ] 35 then 36 blocks=$MINBLOCKS # 至少要有40块. 37 fi 38 39 40 echo "Creating swap file of size $blocks blocks (KB)." 41 dd if=/dev/zero of=$FILE bs=$BLOCKSIZE count=$blocks # 用零填充文件. 42 43 mkswap $FILE $blocks # 将其指定为交换文件(译者注: 或称为交换分区). 44 swapon $FILE # 激活交换文件. 45 46 echo "Swap file created and activated." 47 48 exit $SUCCESS</PRE></FONT></TD></TR></TABLE><HR></DIV><P><TTCLASS="FILENAME">/dev/zero</TT>还有其他的应用场合, 比如当你出于特殊目的, 需要<SPANCLASS="QUOTE">"用0填充"</SPAN>一个指定大小的文件时, 就可以使用它. 举个例子, 比如要将一个文件系统挂载到<AHREF="devref1.html#LOOPBACKREF">环回设备(loopback device)</A>上(请参考<AHREF="system.html#CREATEFS">例子 13-8</A>), 或者想<SPANCLASS="QUOTE">"安全"</SPAN>的删除一个文件(请参考<AHREF="extmisc.html#BLOTOUT">例子 12-55</A>). </P><DIVCLASS="EXAMPLE"><HR><ANAME="RAMDISK"></A><P><B>例子 28-3. 创建一个ramdisk</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # ramdisk.sh 3 4 # 一个"ramdisk"就是系统RAM内存中的一部分, 5 #+ 只不过它被当作文件系统来操作. 6 # 它的优点是访问速度非常快(读/写时间快). 7 # 缺点: 易失性, 当机器重启或关机时, 会丢失数组. 8 #+ 而且会减少系统可用的RAM. 9 # 10 # 那么ramdisk有什么用呢? 11 # 保存一个大数据集, 比如保存表格或字典. 12 #+ 这样的话, 可以增加查询速度, 因为访问内存比访问硬盘快得多. 13 14 15 E_NON_ROOT_USER=70 # 必须以root身份来运行. 16 ROOTUSER_NAME=root 17 18 MOUNTPT=/mnt/ramdisk 19 SIZE=2000 # 2K个块(可以进行适当的修改) 20 BLOCKSIZE=1024 # 每块的大小为1K(1024字节) 21 DEVICE=/dev/ram0 # 第一个ram设备 22 23 username=`id -nu` 24 if [ "$username" != "$ROOTUSER_NAME" ] 25 then 26 echo "Must be root to run \"`basename $0`\"." 27 exit $E_NON_ROOT_USER 28 fi 29 30 if [ ! -d "$MOUNTPT" ] # 测试挂载点是否已经存在, 31 then #+ 如果做了这个判断的话, 当脚本运行多次的时候, 32 mkdir $MOUNTPT #+ 就不会报错了. (译者注: 主要是为了避免多次创建目录.) 33 fi 34 35 dd if=/dev/zero of=$DEVICE count=$SIZE bs=$BLOCKSIZE # 把RAM设备的内容用0填充. 36 # 为什么必须这么做? 37 mke2fs $DEVICE # 在RAM上创建一个ext2文件系统. 38 mount $DEVICE $MOUNTPT # 挂载上. 39 chmod 777 $MOUNTPT # 使一般用户也可以访问这个ramdisk. 40 # 然而, 只能使用root身份来卸载它. 41 42 echo "\"$MOUNTPT\" now available for use." 43 # 现在ramdisk就可以访问了, 即使是普通用户也可以访问. 44 45 # 小心, ramdisk存在易失性, 46 #+ 如果重启或关机的话, 保存的内容就会消失. 47 # 所以, 还是要将你想保存的文件, 保存到常规磁盘目录下. 48 49 # 重启之后, 运行这个脚本, 将会再次建立一个ramdisk. 50 # 如果你仅仅重新加载/mnt/ramdisk, 而没有运行其他步骤的话, 那就不会正常工作. 51 52 # 如果对这个脚本进行适当的改进, 就可以将其放入/etc/rc.d/rc.local中, 53 #+ 这样, 在系统启动的时候就会自动建立一个ramdisk. 54 # 这么做非常适合于那些对速度要求很高的数据库服务器. 55 56 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>最后值得一提的是, ELF二进制文件需要使用<TTCLASS="FILENAME">/dev/zero</TT>. </P></DD></DL></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="procref1.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="debugging.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><TTCLASS="FILENAME">/proc</TT></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="part4.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">调试</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -