📄 communications.html
字号:
38 39 40 # rsync exclude模式 41 # 使用"#"临时注释掉一些不需要的包. 42 EXCLUDE=( 43 /1 44 /2 45 /3 46 /testing 47 /4/SRPMS 48 /4/ppc 49 /4/x86_64 50 /4/i386/debug 51 "/4/i386/kde-i18n-*" 52 "/4/i386/openoffice.org-langpack-*" 53 "/4/i386/*i586.rpm" 54 "/4/i386/GFS-*" 55 "/4/i386/cman-*" 56 "/4/i386/dlm-*" 57 "/4/i386/gnbd-*" 58 "/4/i386/kernel-smp*" 59 # "/4/i386/kernel-xen*" 60 # "/4/i386/xen-*" 61 ) 62 63 64 init () { 65 # 让管道命令返回可能的rsync错误, 比如, 网络延时(stalled network). 66 set -o pipefail 67 68 TMP=${TMPDIR:-/tmp}/${0##*/}.$$ # 保存精炼的下载列表. 69 trap "{ 70 rm -f $TMP 2>/dev/null 71 }" EXIT # 删除存在的临时文件. 72 } 73 74 75 check_pid () { 76 # 检查进程是否存在. 77 if [ -s "$PID_FILE" ]; then 78 echo "PID file exists. Checking ..." 79 PID=$(/bin/egrep -o "^[[:digit:]]+" $PID_FILE) 80 if /bin/ps --pid $PID &>/dev/null; then 81 echo "Process $PID found. ${0##*/} seems to be running!" 82 /usr/bin/logger -t ${0##*/} \ 83 "Process $PID found. ${0##*/} seems to be running!" 84 exit $E_RETURN 85 fi 86 echo "Process $PID not found. Start new process . . ." 87 fi 88 } 89 90 91 # 根据上边的模式, 92 #+ 设置整个文件的更新范围, 从root或$URL开始. 93 set_range () { 94 include= 95 exclude= 96 for p in "${INCLUDE[@]}"; do 97 include="$include --include \"$p\"" 98 done 99 100 for p in "${EXCLUDE[@]}"; do101 exclude="$exclude --exclude \"$p\""102 done103 }104 105 106 # 获得并提炼rsync更新列表.107 get_list () {108 echo $$ > $PID_FILE || {109 echo "Can't write to pid file $PID_FILE"110 exit $E_RETURN111 }112 113 echo -n "Retrieving and refining update list . . ."114 115 # 获得列表 -- 作为单个命令来运行rsync的话需要'eval'.116 # $3和$4是文件创建的日期和时间.117 # $5是完整的包名字.118 previous=119 pre_file=120 pre_date=0121 eval /bin/nice /usr/bin/rsync \122 -r $include $exclude $URL | \123 egrep '^dr.x|^-r' | \124 awk '{print $3, $4, $5}' | \125 sort -k3 | \126 { while read line; do127 # 获得这段运行的秒数, 过滤掉不用的包. 128 cur_date=$(date -d "$(echo $line | awk '{print $1, $2}')" +%s)129 # echo $cur_date130 131 # 取得文件名. 132 cur_file=$(echo $line | awk '{print $3}')133 # echo $cur_file134 135 # 如果可能的话, 从文件名中取得rpm的包名字. 136 if [[ $cur_file == *rpm ]]; then137 pkg_name=$(echo $cur_file | sed -r -e \138 's/(^([^_-]+[_-])+)[[:digit:]]+\..*[_-].*$/\1/')139 else140 pkg_name=141 fi142 # echo $pkg_name143 144 if [ -z "$pkg_name" ]; then # 如果不是一个rpm文件,145 echo $cur_file >> $TMP #+ 然后添加到下载列表里.146 elif [ "$pkg_name" != "$previous" ]; then # 发现一个新包.147 echo $pre_file >> $TMP # 输出最新的文件.148 previous=$pkg_name # 保存当前状态.149 pre_date=$cur_date150 pre_file=$cur_file151 elif [ "$cur_date" -gt "$pre_date" ]; then # 如果是相同的包, 但是这个包更新一些, 152 pre_date=$cur_date #+ 那么就更新最新的. 153 pre_file=$cur_file154 fi155 done156 echo $pre_file >> $TMP # TMP现在包含所有157 #+ 提炼过的列表. 158 # echo "subshell=$BASH_SUBSHELL"159 160 } # 这里的大括号是为了让最后这句"echo $pre_file >> $TMP"161 # 也能与整个循环一起放到同一个子shell ( 1 )中. 162 163 RET=$? # 取得管道命令的返回状态. 164 165 [ "$RET" -ne 0 ] && {166 echo "List retrieving failed with code $RET"167 exit $E_RETURN168 }169 170 echo "done"; echo171 }172 173 # 真正的rsync下载部分. 174 get_file () {175 176 echo "Downloading..."177 /bin/nice /usr/bin/rsync \178 $OPTS \179 --filter "merge,+/ $TMP" \180 --exclude '*' \181 $URL $DEST \182 | /usr/bin/tee $LOG183 184 RET=$?185 186 # --filter merge,+/ 对于这个目的来说, 这句是至关重要的. 187 # + 修饰语意为着包含, / 意味着绝对路径. 188 # 然后$TMP中排过序的列表将会包含升序的路径名, 189 #+ 并从"简化的流程"(shortcutting the circuit)中阻止下边的 --exclude '*'. 190 191 echo "Done"192 193 rm -f $PID_FILE 2>/dev/null194 195 return $RET196 }197 198 # -------199 # Main200 init201 check_pid202 set_range203 get_list204 get_file205 RET=$?206 # -------207 208 if [ "$RET" -eq 0 ]; then209 /usr/bin/logger -t ${0##*/} "Fedora update mirrored successfully."210 else211 /usr/bin/logger -t ${0##*/} "Fedora update mirrored with failure code: $RET"212 fi213 214 exit $RET</PRE></FONT></TD></TR></TABLE><HR></DIV><P>在使用<BCLASS="COMMAND">rcp</B>, <BCLASS="COMMAND">rsync</B>, 还有另外一些有安全问题的类似工具的时候, 一定要小心, 因为将这些工具用在shell脚本中是不明智的. 你应该考虑使用<BCLASS="COMMAND">ssh</B>, <BCLASS="COMMAND">scp</B>, 或者<BCLASS="COMMAND">expect</B>脚本来代替这些不安全的工具. </P></DD><DT><ANAME="SSHREF"></A><BCLASS="COMMAND">ssh</B></DT><DD><P><TTCLASS="REPLACEABLE"><I>安全shell</I></TT>, 登陆远端主机并在其上运行命令. 这个工具具有身份认证和加密的功能, 可以安全的替换<BCLASS="COMMAND">telnet</B>, <BCLASS="COMMAND">rlogin</B>, <BCLASS="COMMAND">rcp</B>, 和<BCLASS="COMMAND">rsh</B>等工具. 请参考这个工具的<EM>man页</EM>来获取详细信息. </P><DIVCLASS="EXAMPLE"><HR><ANAME="REMOTE"></A><P><B>例子 12-40. 使用ssh</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # remote.bash: 使用ssh. 3 4 # 这个例子是Michael Zick编写的. 5 # 授权在本书中使用. 6 7 8 # 假设的一些前提: 9 # --------------- 10 # fd-2(文件描述符2)的内容并没有被丢弃( '2>/dev/null' ). 11 # ssh/sshd假设stderr ('2')将会显示给用户. 12 # 13 # 假设sshd正运行在你的机器上. 14 # 对于绝大多数'标准'的发行版, 都是有sshd的, 15 #+ 并且没有稀奇古怪的ssh-keygen. 16 17 # 在你的机器上从命令行中试着运行一下ssh: 18 # 19 # $ ssh $HOSTNAME 20 # 不需要特别的设置, 也会要求你输入密码. 21 # 接下来输入密码, 22 # 完成后, $ exit 23 # 24 # 能够正常运行么? 如果正常的话, 接下来你可以获得更多的乐趣了. 25 26 # 尝试在你的机器上以'root'身份来运行ssh: 27 # 28 # $ ssh -l root $HOSTNAME 29 # 当要求询问密码时, 输入root的密码, 注意别输入你的用户密码. 30 # Last login: Tue Aug 10 20:25:49 2004 from localhost.localdomain 31 # 完成后键入'exit'. 32 33 # 上边的动作将会带给你一个交互的shell. 34 # 也可以在'single command'模式下建立sshd, 35 #+ 但是这已经超出本例所讲解的范围了. 36 # 唯一需要注意的是, 下面的命令都可以运行在 37 #+ 'single command'模式下. 38 39 40 # 基本的, 写stdout(本地)命令. 41 42 ls -l 43 44 # 这样远端机器上就会执行相同的命令. 45 # 如果你想的话, 可以传递不同的'USERNAME'和'HOSTNAME': 46 USER=${USERNAME:-$(whoami)} 47 HOST=${HOSTNAME:-$(hostname)} 48 49 # 现在, 在远端主机上执行上边的命令, 50 #+ 当然, 所有的传输都会被加密. 51 52 ssh -l ${USER} ${HOST} " ls -l " 53 54 # 期望的结果就是在远端主机上列出 55 #+ 你的用户名所拥有的主目录下的所有文件. 56 # 如果想看点不一样的东西, 57 #+ 那就在别的地方运行这个脚本, 别在你自己的主目录下运行这个脚本. 58 59 # 换句话说, Bash命令已经作为一个引用行 60 #+ 被传递到了远端shell中, 这样远端机器就会运行它. 61 # 在这种情况下, sshd代表你运行了' bash -c "ls -l" '. 62 63 # 如果你想不输入密码, 64 #+ 或者想更详细的了解相关的问题, 请参考: 65 #+ man ssh 66 #+ man ssh-keygen 67 #+ man sshd_config. 68 69 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="CAUTION"><P></P><TABLECLASS="CAUTION"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/caution.gif"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>在循环中, <BCLASS="COMMAND">ssh</B>可能会引起一些异常问题. 根据comp.unix上的shell文档<AHREF="http://groups-beta.google.com/group/comp.unix.shell/msg/dcb446b5fff7d230"TARGET="_top"> Usenet post</A>所描述的内容, <BCLASS="COMMAND">ssh</B>继承了循环的<TTCLASS="FILENAME">stdin</TT>. 为了解决这个问题, 请使用<BCLASS="COMMAND">ssh</B>的<CODECLASS="OPTION">-n</CODE>或者<CODECLASS="OPTION">-f</CODE>选项. </P><P>感谢, Jason Bechtel, 为我们指出这个问题. </P></TD></TR></TABLE></DIV></DD><DT><BCLASS="COMMAND">scp</B></DT><DD><P><TTCLASS="REPLACEABLE"><I>安全拷贝</I></TT>, 在功能上与<BCLASS="COMMAND">rcp</B>很相似, 就是在两个不同的网络主机之间拷贝文件, 但是要使用鉴权的方式, 并且要使用与<BCLASS="COMMAND">ssh</B>类似的安全层. </P></DD></DL></DIV><P></P><DIVCLASS="VARIABLELIST"><P><B><ANAME="COMMLOCAL1"></A>本地网络</B></P><DL><DT><ANAME="WRITEREF"></A><BCLASS="COMMAND">write</B></DT><DD><P>这是一个端到端通讯的工具. 这个工具可以从你的终端上(console或者<ICLASS="FIRSTTERM">xterm</I>)发送整行数据到另一个用户的终端上. <AHREF="system.html#MESGREF">mesg</A>命令当然也可以用来禁用对于一个终端的写权限. </P><P>因为<BCLASS="COMMAND">write</B>命令是需要交互的, 所以这个命令在脚本中很少使用. </P></DD><DT><BCLASS="COMMAND">netconfig</B></DT><DD><P>用来配置网络适配器(使用DHCP)的命令行工具. 这个命令对于红帽发行版来说是内置的. </P></DD></DL></DIV><P></P><DIVCLASS="VARIABLELIST"><P><B><ANAME="COMMMAIL1"></A>Mail</B></P><DL><DT><BCLASS="COMMAND">mail</B></DT><DD><P>发送或者读取e-mail消息. </P><P>如果把这个命令行的mail客户端当成一个脚本中的命令来使用的话, 效果非常好. </P><DIVCLASS="EXAMPLE"><HR><ANAME="SELFMAILER"></A><P><B>例子 12-41. 一个mail自身的脚本</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/sh 2 # self-mailer.sh: mail自身的脚本. 3 4 adr=${1:-`whoami`} # 如果没有指定的话, 默认是当前用户. 5 # 键入'self-mailer.sh wiseguy@superdupergenius.com' 6 #+ 将脚本发送到这个地址. 7 # 如果只键入'self-mailer.sh'(不给参数)的话, 8 #+ 那么这个脚本就会被发送给调用者, 比如, 比如, bozo@localhost.localdomain. 9 # 10 # 如果想了解${parameter:-default}结构的更多细节, 11 #+ 请参考"变量重游"那章中的 12 #+ "参数替换"小节. 13 14 # ============================================================================ 15 cat $0 | mail -s "Script \"`basename $0`\" has mailed itself to you." "$adr" 16 # ============================================================================ 17 18 # -------------------------------------------- 19 # 来自self-mailing脚本的一份祝福. 20 # 一个喜欢恶搞的家伙运行了这个脚本, 21 #+ 这导致了他自己收到了这份mail. 22 # 显然的, 有些人确实没什么事好做, 23 #+ 就只能浪费他们自己的时间玩了. 24 # -------------------------------------------- 25 26 echo "At `date`, script \"`basename $0`\" mailed to "$adr"." 27 28 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><BCLASS="COMMAND">mailto</B></DT><DD><P>与<BCLASS="COMMAND">mail</B>命令很相似, <BCLASS="COMMAND">mailto</B>可以使用命令行或在脚本中发送e-mail消息. 而且<BCLASS="COMMAND">mailto</B>也可以发送MIME(多媒体)消息. </P></DD><DT><BCLASS="COMMAND">vacation</B></DT><DD><P>这个工具可以自动回复e-mail给发送者, 表示邮件的接受者正在度假暂时无法收到邮件. 这个工具与<BCLASS="COMMAND">sendmail</B>一起运行于网络上, 并且这个工具不支持拨号的POPmail帐号. </P></DD></DL></DIV></DIV><H3CLASS="FOOTNOTES">注意事项</H3><TABLEBORDER="0"CLASS="FOOTNOTES"WIDTH="100%"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN9898"HREF="communications.html#AEN9898"><SPANCLASS="footnote">[1]</SPAN></A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P><ANAME="DAEMONREF"></A></P><P>一个<EM>幽灵进程</EM>指的是并未附加在终端会话中的后台进程. 幽灵进程在指定的时间执行指定的服务, 或者由特定的事件触发来执行指定的服务. </P><P>希腊文中的<SPANCLASS="QUOTE">"daemon"</SPAN>意思是幽灵, 这个词充满了神秘感和神奇的力量, 在UNIX中幽灵进程总是在后台默默地执行着分配给它们的任务. </P></TD></TR></TABLE><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="filearchiv.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="terminalccmds.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">文件与归档命令</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="external.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 + -