Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting | ||
---|---|---|
Prev | Chapter 12. External Filters, Programs and Commands | Next |
下边命令中的某几个命令你会在 "追踪垃圾邮件" 练习中找到其用法, 用来进行网络数据的转换和分析.
通过名字或 IP 地址来搜索一个互联网主机的信息, 使用 DNS.
bash$ host surfacemail.com surfacemail.com. has address 202.92.42.236 |
显示一个主机 IP 信息. 使用 -h 选项, ipcalc 将会做一个 DNS 的反向查询, 通过 IP 地址找到主机(服务器)名.
bash$ ipcalc -h 202.92.42.236 HOSTNAME=surfacemail.com |
通过 IP 地址在一个主机上做一个互联网的 "名字服务查询". 事实上这与 ipcalc -h 或 dig -x 等价. 这个命令既可以交互运行也可以非交互运行, 换句话说, 就是在脚本中运行.
nslookup 命令据说已经慢慢被"忽视"了, 但是它还是有它的用处.
bash$ nslookup -sil 66.97.104.180 nslookup kuhleersparnis.ch Server: 135.116.137.2 Address: 135.116.137.2#53 Non-authoritative answer: Name: kuhleersparnis.ch |
域信息查询. 与 nslookup 很相似, dig 在一个主机上做一个互联网的 "名字服务查询". 这个命令既可以交互运行也可以非交互运行, 换句话说, 就是在脚本中运行.
下边是一些 dig 命令有趣的选项, +time=N 选项用来设置查询超时为 N 秒, +nofail 选项用来持续查询服务器直到收到一个响应, -x 选项会做反向地址查询.
比较下边这3个命令的输出, dig -x , ipcalc -h 和 nslookup.
bash$ dig -x 81.9.6.2 ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11649 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;2.6.9.81.in-addr.arpa. IN PTR ;; AUTHORITY SECTION: 6.9.81.in-addr.arpa. 3600 IN SOA ns.eltel.net. noc.eltel.net. 2002031705 900 600 86400 3600 ;; Query time: 537 msec ;; SERVER: 135.116.137.2#53(135.116.137.2) ;; WHEN: Wed Jun 26 08:35:24 2002 ;; MSG SIZE rcvd: 91 |
Example 12-36. 查找滥用的连接来报告垃圾邮件发送者
1 #!/bin/bash 2 # spam-lookup.sh: 查找滥用的连接来报告垃圾邮件发送者. 3 # 感谢 Michael Zick. 4 5 # 检查命令行参数. 6 ARGCOUNT=1 7 E_WRONGARGS=65 8 if [ $# -ne "$ARGCOUNT" ] 9 then 10 echo "Usage: `basename $0` domain-name" 11 exit $E_WRONGARGS 12 fi 13 14 15 dig +short $1.contacts.abuse.net -c in -t txt 16 # 也试试: 17 # dig +nssearch $1 18 # 尽量找到 "可信赖的名字服务器" 并且显示 SOA 记录. 19 20 # 下边这句也可以: 21 # whois -h whois.abuse.net $1 22 # ^^ ^^^^^^^^^^^^^^^ 指定主机. 23 # 使用这个命令也可以查找多个垃圾邮件发送者, 比如:" 24 # whois -h whois.abuse.net $spamdomain1 $spamdomain2 . . . 25 26 27 # 练习: 28 # ----- 29 # 扩展这个脚本的功能, 30 #+ 让它可以自动发送 e-mail 来通知 31 #+ 需要对此负责的 ISP 的联系地址. 32 # 暗示: 使用 "mail" 命令. 33 34 exit $? 35 36 # spam-lookup.sh chinatietong.com 37 # 一个已知的垃圾邮件域.(译者: 中国铁通. . .) 38 39 # "crnet_mgr@chinatietong.com" 40 # "crnet_tec@chinatietong.com" 41 # "postmaster@chinatietong.com" 42 43 44 # 如果想找到这个脚本的一个更详尽的版本, 45 #+ 请访问 SpamViz 的主页, http://www.spamviz.net/index.html. |
Example 12-37. 分析一个垃圾邮件域<rojy bug>
1 #! /bin/bash 2 # is-spammer.sh: 鉴别一个垃圾邮件域 3 4 # $Id: is-spammer, v 1.4 2004/09/01 19:37:52 mszick Exp $ 5 # 上边这行是 RCS ID 信息. 6 # 7 # 这是附件中捐献脚本 is_spammer.bash 8 #+ 的一个简单版本. 9 10 # is-spammer <domain.name> 11 12 # 使用外部程序: 'dig' 13 # 测试版本: 9.2.4rc5 14 15 # 使用函数. 16 # 使用 IFS 来分析分配在数组中的字符串. 17 # 检查 e-mail 黑名单. 18 19 # 使用来自文本体中的 domain.name: 20 # http://www.good_stuff.spammer.biz/just_ignore_everything_else 21 # ^^^^^^^^^^^ 22 # 或者使用来自任意 e-mail 地址的 domain.name: 23 # Really_Good_Offer@spammer.biz 24 # 25 # 并将其作为这个脚本的唯一参数. 26 #(另: 你的 Inet 连接应该保证连接) 27 # 28 # 这样, 在上边两个实例中调用这个脚本: 29 # is-spammer.sh spammer.biz 30 31 32 # Whitespace == :Space:Tab:Line Feed:Carriage Return: 33 WSP_IFS=$'\x20'$'\x09'$'\x0A'$'\x0D' 34 35 # No Whitespace == Line Feed:Carriage Return 36 No_WSP=$'\x0A'$'\x0D' 37 38 # 域分隔符为点分10进制 ip 地址 39 ADR_IFS=${No_WSP}'.' 40 41 # 取得 dns 文本资源记录. 42 # get_txt <error_code> <list_query> 43 get_txt() { 44 45 # 分析在"."中分配的 $1. 46 local -a dns 47 IFS=$ADR_IFS 48 dns=( $1 ) 49 IFS=$WSP_IFS 50 if [ "${dns[0]}" == '127' ] 51 then 52 # 查看此处是否有原因. 53 echo $(dig +short $2 -t txt) 54 fi 55 } 56 57 # 取得 dns 地址资源记录. 58 # chk_adr <rev_dns> <list_server> 59 chk_adr() { 60 local reply 61 local server 62 local reason 63 64 server=${1}${2} 65 reply=$( dig +short ${server} ) 66 67 # 假设应答可能是一个错误码 . . . 68 if [ ${#reply} -gt 6 ] 69 then 70 reason=$(get_txt ${reply} ${server} ) 71 reason=${reason:-${reply}} 72 fi 73 echo ${reason:-' not blacklisted.'} 74 } 75 76 # 需要从名字中取得 IP 地址. 77 echo 'Get address of: '$1 78 ip_adr=$(dig +short $1) 79 dns_reply=${ip_adr:-' no answer '} 80 echo ' Found address: '${dns_reply} 81 82 # 一个可用的应答至少是4个数字加上3个点. 83 if [ ${#ip_adr} -gt 6 ] 84 then 85 echo 86 declare query 87 88 # 分析点中的分配. 89 declare -a dns 90 IFS=$ADR_IFS 91 dns=( ${ip_adr} ) 92 IFS=$WSP_IFS 93 94 # Reorder octets into dns query order. 95 rev_dns="${dns[3]}"'.'"${dns[2]}"'.'"${dns[1]}"'.'"${dns[0]}"'.' 96 97 # 参见: http://www.spamhaus.org (Conservative, well maintained) 98 echo -n 'spamhaus.org says: ' 99 echo $(chk_adr ${rev_dns} 'sbl-xbl.spamhaus.org') 100 101 # 参见: http://ordb.org (Open mail relays) 102 echo -n ' ordb.org says: ' 103 echo $(chk_adr ${rev_dns} 'relays.ordb.org') 104 105 # 参见: http://www.spamcop.net/ (你可以在这里报告 spammer) 106 echo -n ' spamcop.net says: ' 107 echo $(chk_adr ${rev_dns} 'bl.spamcop.net') 108 109 # # # 其他的黑名单操作 # # # 110 111 # 参见: http://cbl.abuseat.org. 112 echo -n ' abuseat.org says: ' 113 echo $(chk_adr ${rev_dns} 'cbl.abuseat.org') 114 115 # 参见: http://dsbl.org/usage (Various mail relays) 116 echo 117 echo 'Distributed Server Listings' 118 echo -n ' list.dsbl.org says: ' 119 echo $(chk_adr ${rev_dns} 'list.dsbl.org') 120 121 echo -n ' multihop.dsbl.org says: ' 122 echo $(chk_adr ${rev_dns} 'multihop.dsbl.org') 123 124 echo -n 'unconfirmed.dsbl.org says: ' 125 echo $(chk_adr ${rev_dns} 'unconfirmed.dsbl.org') 126 127 else 128 echo 129 echo 'Could not use that address.' 130 fi 131 132 exit 0 133 134 # 练习: 135 # ----- 136 137 # 1) 检查脚本的参数, 138 # 并且如果必要的话使用合适的错误消息退出. 139 140 # 2) 检查调用这个脚本的时候是否在线, 141 # 并且如果必要的话使用合适的错误消息退出. 142 143 # 3) Substitute generic variables for "hard-coded" BHL domains. 144 145 # 4) 通过对 'dig' 命令使用 "+time=" 选项 146 来给这个脚本设置一个暂停. |
想获得比上边这个脚本更详细的版本, 参见 Example A-27.
跟踪包发送到远端主机过程中的路由信息. 这个命令在 LAN, WAN, 或者在 Internet 上都可以正常工作. 远端主机可以通过 IP 地址来指定. 这个命令的输出也可以通过管道中的 grep 或 sed 命令来过滤.
bash$ traceroute 81.9.6.2 traceroute to 81.9.6.2 (81.9.6.2), 30 hops max, 38 byte packets 1 tc43.xjbnnbrb.com (136.30.178.8) 191.303 ms 179.400 ms 179.767 ms 2 or0.xjbnnbrb.com (136.30.178.1) 179.536 ms 179.534 ms 169.685 ms 3 192.168.11.101 (192.168.11.101) 189.471 ms 189.556 ms * ... |
广播一个 "ICMP ECHO_REQUEST" 包到其他主机上, 既可以是本地网络也可以使远端网络. 这是一个测试网络连接的诊断工具, 应该小心使用.
一个成功的 ping 返回的 退出码 为 0. 可以用在脚本的测试语句中.
bash$ ping localhost PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data. 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec --- localhost.localdomain ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms |
执行DNS (域名系统) 查询lookup. -h 选项允许指定需要查询的特定的 whois 服务器. 参见 Example 4-6 和 Example 12-36.
取得网络上的用户信息. 另外这个命令可以显示一个用户的~/.plan, ~/.project, 和 ~/.forward 文件, 如果存在的话.
bash$ finger Login Name Tty Idle Login Time Office Office Phone bozo Bozo Bozeman tty1 8 Jun 25 16:59 bozo Bozo Bozeman ttyp0 Jun 25 16:59 bozo Bozo Bozeman ttyp1 Jun 25 17:07 bash$ finger bozo Login: bozo Name: Bozo Bozeman Directory: /home/bozo Shell: /bin/bash Office: 2355 Clown St., 543-1234 On since Fri Aug 31 20:13 (MST) on tty1 1 hour 38 minutes idle On since Fri Aug 31 20:13 (MST) on pts/0 12 seconds idle On since Fri Aug 31 20:13 (MST) on pts/1 On since Fri Aug 31 20:31 (MST) on pts/2 1 hour 16 minutes idle No mail. No Plan. |
处于安全上的考虑, 许多网络都禁用了 finger 以及和它相关的幽灵进程. [1]
修改 finger 命令所显示出来的用户信息.
验证一个互联网的 e-mail 地址.
sx 和 rx 命令使用 xmodem 协议, 设置服务来向远端主机传输文件和接收文件. 这些都是通讯安装包的一般部分, 比如 minicom.
sz 和 rz 命令使用 zmodem 协议, 设置服务来向远端主机传输文件和接收文件. zmodem 协议在某些方面比 xmodem强, 比如使用更快的的传输波特率, 并且可以对中断的文件进行续传.与 sx 一样 rx, 这些都是通讯安装包的一般部分.
向远端服务器上传或下载的工具和协议. 一个ftp会话可以写到脚本中自动运行. (见 Example 17-6, Example A-4, 和 Example A-13).
uucp: UNIX 到 UNIX 拷贝. 这是一个通讯安装包, 目的是为了在 UNIX 服务器之间传输文件. 使用 shell 脚本来处理 uucp 命令序列是一种有效的方法.
因为互联网和电子邮件的出现, uucp 现在看起来已经很落伍了, 但是这个命令在互联网连接不可用或者不适合使用的地方, 这个命令还是可以完美的运行. uucp 的优点就是它的容错性, 即使有一个服务将拷贝操作中断了, 那么当连接恢复的时候, 这个命令还是可以在中断的地方续传.
---
uux: UNIX 到 UNIX 执行. 在远端系统上执行一个命令.这个命令是 uucp 包的一部分.
---
cu: Call Up 一个远端系统并且作为一个简单终端进行连接. 这是一个 telnet 的缩减版本. 这个命令是 uucp 包的一部分.
连接远端主机的工具和协议.
telnet 协议本身包含安全漏洞, 因此我们应该适当的避免使用. |
wget 工具使用非交互的形式从 web 或 ftp 站点上取得或下载文件. 在脚本中使用正好.
1 wget -p http://www.xyz23.com/file01.html 2 # The -p or --page-requisite 选项将会使得 wget 取得显示指定页时 3 #+ 所需要的所有文件.(译者: 比如内嵌图片和样式表等). 4 5 wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -O $SAVEFILE 6 # -r 选项将会递归的从指定站点 7 #+ 上下载所有连接. |
Example 12-38. 获得一份股票报价
1 #!/bin/bash 2 # quote-fetch.sh: 下载一份股票报价. 3 4 5 E_NOPARAMS=66 6 7 if [ -z "$1" ] # 必须指定需要获取的股票(代号). 8 then echo "Usage: `basename $0` stock-symbol" 9 exit $E_NOPARAMS 10 fi 11 12 stock_symbol=$1 13 14 file_suffix=.html 15 # 获得一个 HTML 文件, 所以要正确命名它. 16 URL='http://finance.yahoo.com/q?s=' 17 # Yahoo 金融板块, 后缀是股票查询. 18 19 # ----------------------------------------------------------- 20 wget -O ${stock_symbol}${file_suffix} "${URL}${stock_symbol}" 21 # ----------------------------------------------------------- 22 23 24 # 在 http://search.yahoo.com 上查询相关材料: 25 # ----------------------------------------------------------- 26 # URL="http://search.yahoo.com/search?fr=ush-news&p=${query}" 27 # wget -O "$savefilename" "${URL}" 28 # ----------------------------------------------------------- 29 # 保存相关 URL 的列表. 30 31 exit $? 32 33 # 练习: 34 # ----- 35 # 36 # 1) 添加一个测试来验证用户正在线. 37 # (暗示: 对 "ppp" 或 "connect" 来分析 'ps -ax' 的输出. 38 # 39 # 2) 修改这个脚本, 让这个脚本具有获得本地天气预报的能力, 40 #+ 将用户的 zip code 作为参数. |
参见 Example A-29 和 Example A-30.
lynx 是一个网页浏览器, 也是一个文件浏览器. 它可以(通过使用 -dump 选项)在脚本中使用. 它的作用是可以从 Web 或 ftp 站点上非交互的获得文件.
1 lynx -dump http://www.xyz23.com/file01.html >$SAVEFILE |
使用 -traversal 选项, lynx 将从参数中指定的 HTTP URL 开始, 遍历指定服务器上的所有链接. 如果与 -crawl 选项一起用的话, 将会把每个输出的页面文本都放到一个 log 文件中.
远端登陆, 在远端的主机上开启一个会话. 这个命令存在安全隐患, 所以要使用 ssh 来代替.
远端 shell, 在远端的主机上执行命令. 这个命令存在安全隐患, 所以要使用 ssh 来代替.
远端拷贝, 在网络上的不同主机间拷贝文件.
远端同步, 在网络上的不同主机间(同步)更新文件.
bash$ rsync -a ~/sourcedir/*txt /node1/subdirectory/ |
Example 12-39. 更新 Fedora 4 <rojy bug>
1 #!/bin/bash 2 # fc4upd.sh 3 4 # 脚本作者: Frank Wang. 5 # 本书作者作了少量修改. 6 # 授权在本书中使用. 7 8 9 # 使用 rsync 命令从镜像站点上下载 Fedora 4 的更新. 10 # 为了节省空间, 如果有多个版本存在的话, 11 #+ 只下载最新的包. 12 13 URL=rsync://distro.ibiblio.org/fedora-linux-core/updates/ 14 # URL=rsync://ftp.kddilabs.jp/fedora/core/updates/ 15 # URL=rsync://rsync.planetmirror.com/fedora-linux-core/updates/ 16 17 DEST=${1:-/var/www/html/fedora/updates/} 18 LOG=/tmp/repo-update-$(/bin/date +%Y-%m-%d).txt 19 PID_FILE=/var/run/${0##*/}.pid 20 21 E_RETURN=65 # 某些意想不到的错误. 22 23 24 # 一搬 rsync 选项 25 # -r: 递归下载 26 # -t: 保存时间 27 # -v: verbose 28 29 OPTS="-rtv --delete-excluded --delete-after --partial" 30 31 # rsync include 模式 32 # Leading slash causes absolute path name match. 33 INCLUDE=( 34 "/4/i386/kde-i18n-Chinese*" 35 # ^ ^ 36 # 双引号是必须的, 用来防止file globbing. 37 ) 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[@]}"; do 101 exclude="$exclude --exclude \"$p\"" 102 done 103 } 104 105 106 # 获得并提炼 rsync 更新列表. 107 get_list () { 108 echo $$ > $PID_FILE || { 109 echo "Can't write to pid file $PID_FILE" 110 exit $E_RETURN 111 } 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=0 121 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; do 127 # 获得这段运行的秒数, 过滤掉不用的包. 128 cur_date=$(date -d "$(echo $line | awk '{print $1, $2}')" +%s) 129 # echo $cur_date 130 131 # 取得文件名. 132 cur_file=$(echo $line | awk '{print $3}') 133 # echo $cur_file 134 135 # 如果可能的话, 从文件名中取得 rpm 的包名字. 136 if [[ $cur_file == *rpm ]]; then 137 pkg_name=$(echo $cur_file | sed -r -e \ 138 's/(^([^_-]+[_-])+)[[:digit:]]+\..*[_-].*$/\1/') 139 else 140 pkg_name= 141 fi 142 # echo $pkg_name 143 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_date 150 pre_file=$cur_file 151 elif [ "$cur_date" -gt "$pre_date" ]; then # 如果是相同的包, 但是更新一些, 152 pre_date=$cur_date #+ 那么就更新最新的. 153 pre_file=$cur_file 154 fi 155 done 156 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_RETURN 168 } 169 170 echo "done"; echo 171 } 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 $LOG 183 184 RET=$? 185 186 # --filter merge,+/ is crucial for the intention. 187 # + modifier means include and / means absolute path. 188 # Then sorted list in $TMP will contain ascending dir name and 189 #+ prevent the following --exclude '*' from "shortcutting the circuit." 190 191 echo "Done" 192 193 rm -f $PID_FILE 2>/dev/null 194 195 return $RET 196 } 197 198 # ------- 199 # Main 200 init 201 check_pid 202 set_range 203 get_list 204 get_file 205 RET=$? 206 # ------- 207 208 if [ "$RET" -eq 0 ]; then 209 /usr/bin/logger -t ${0##*/} "Fedora update mirrored successfully." 210 else 211 /usr/bin/logger -t ${0##*/} "Fedora update mirrored with failure code: $RET" 212 fi 213 214 exit $RET |
使用 rcp, rsync, 和其他一些有安全问题的类似工具, 并将这些工具用在 shell 脚本中是不明智的. 应该考虑使用 ssh, scp, 或者一个 expect 脚本来代替这些不安全的工具.
安全 shell, 登陆远端主机并在其上运行命令. 这个工具具有身份认证和加密的功能, 可以安全的替换 telnet, rlogin, rcp, 和 rsh 等工具. 参见 man页 来获取详细信息.
Example 12-40. 使用 ssh
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 # 对于大多数 '标准' 的发行版, 是应该有的, 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 是可能的, <rojy bug> 35 #+ 不过这已经超出本例的范围了. 36 # 唯一需要注意的事情是下面都可以工作在 37 #+ 'single command' 模式. 38 39 40 # 一个基本的写输出(本地)命令. 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 #+ username 主目录的所有文件. 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 |
在循环中, ssh 可能会引起意想不到的异常行为. 根据comp.unix 上的shell文档 Usenet post , ssh 继承了循环的标准输入.为了解决这个问题, 使用 ssh 的 -n 或者 -f 选项. 感谢 Jason Bechtel, 指出这点. |
安全拷贝, 在功能上与 rcp 很相似, 就是在2个不同的网络主机之间拷贝文件, 但是要通过鉴权的方式, 并且使用与 ssh 类似的安全层.
这是一个端到端通讯的工具. 这个工具可以从你的终端上(console 或者 xterm)发送整行到另一个用户的终端上. mesg 命令当然也可以用来对于一个终端的写权限
因为 write 是需要交互的, 所以这个命令通常不使用在脚本中.
用来配置网络适配器(使用 DHCP)的命令行工具. 这个命令对于红帽发行版来说是内置的.
发送或读取 e-mail 消息.
如果把这个命令行的 mail 客户端当成一个脚本中的命令来使用的话, 效果非常好.
Example 12-41. 一个可以mail自己的脚本
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 #+ 请参见第9章 变量重游中的 12 #+ 第3节 参数替换. 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 |
与 mail 命令很相似, mailto 命令可以使用命令行或在脚本中发送 e-mail 消息. 然而, mailto 命令也允许发送 MIME (多媒体) 消息.
这个工具可以自动回复 e-mail 给发送者, 表示邮件的接受者正在度假暂时无法收到邮件. 这个工具与 sendmail 一起运行于网络上, 并且这个工具不支持拨号的 POPmail 帐号.
[1] |
一个 幽灵进程 指的是并未附加在终端会话中的后台进程. 幽灵进程 在指定的时间执行指定的服务, 或者由特定的事件出发来执行指定的服务. 希腊文中的 "daemon" 意思是幽灵, 这个词充满了神秘感和神奇的力量, 在 UNIX 中幽灵进程总是在后台默默地执行着分配给它们的任务. |