UNIX 新手指南: 一些很好的 Shell 诀窍( 九 )


清单 33. 从管道读取
$ ls | while read file; do ls $file; done
10
11
12
$
您还可以跨多行操作变量,比如将一条消息发送到标准输出,然后对 loopname 变量执行 Shell 运算(请参见 Shell 运算和进制转换部分) 。尝试清单 34 中提供的示例:
清单 34. 使用管道读取的较长循环
$ ls | while read file; do echo "The file is " `ls -i $file`;
echo "If the number were in hex, the value would be $((16#$file))"done
The file is 100267120 10
If the number were in hex, the value would be 16
The file is 100267121 11
If the number were in hex, the value would be 17
The file is 100267122 12
If the number were in hex, the value would be 18
$
您可以在一个管道输入的 read 中读取多个值,如清单 35 中所示 。
清单 35. 从一个管道读取多个变量
$ ls -i | while read inode file; do
echo "File $file has inode $inode"done
File 10 has inode 100267120
File 11 has inode 100267121
File 12 has inode 100267122
$
实际运用
此结束部分将您在前面学到的诀窍和技术加以组合来实现在实际中有用的单命令行程序 。它还包括一个简单的 Shell 脚本——执行任意进制的转换 。
有用的单命令行程序
以下示例是执行有用功能的 Shell 单命令行程序样本 。它们全部由本教程中描述的各种结构组成 。
从当前目录中获取一组文件名恰好为两个字符长的文件,并使用 .ppm 扩展名为其重新命名:
for i in ??; { mv $i $i.ppm; }
使用 tar 和 Subshell 复制整个目录树,同时保持相同的文件权限:
( cd source ; tar pcf - * ) | ( cd target ; tar pxvf - )
读取二进制数并以十进制输出值:
read BINLOC;echo $((2#$BINLOC))
在 /usr/local 目录树中找到所有带 .MP3 扩展名的文件(这些文件的名称中可能包含空格字符),然后使用 bzip2 实用程序压缩这些文件:
find /usr/local -name "*.mp3" | while read name ; do bzip2 $name; done
将给定文件中所有十进制数的值以十六进制输出:
cat file | while read number ; do echo $((0x$number)); done
将给定文件中所有十进制数转换为十六进制的值,并将值输出到带有 .hex 扩展名的新文件中:
cat file | while read number ; do echo $((0x$number)) >> file.hex; done
构造重复十次的循环,以数字(从 0 到 90 以 10 递增)作为传递的参数运行 command:
i=0; while [ $i -ne 100 ]; do command $i; i=$(($i 10)); done
示例脚本:将数字转换为其他进制
本教程中讨论的一些诀窍在清单 36 中被组合在一起 。它是一个示例脚本——baseconv,将数字从给定的输入进制转换为输出进制 。为它提供输入进制和输出进制的值作为参数,然后它从键盘输入读取数字,直到读取了数字 0 。
清单 36. 转换进制的简单脚本
#!/bin/sh
# baseconv, convert numbers from one base to another.
#
NUMBER=1
while [ $NUMBER ]; do
read -p "Input base: " IN
read -p "Output base: " OUT
read -p "Number: " NUMBER
bc -ql <<- EOF
obase=$OUT
ibase=$IN
$NUMBER
EOF
done
当您把它保存到可执行文件后(请参见创建 Shell 脚本部分),尝试运行该文件,如清单 37 中所示:
清单 37. baseconv 脚本的输出
$ ./baseconv
Input base: 10
Output base: 16
Number: 33
21
Input base: 2
Output base: 1100
Number: 101
5
Input base: 16
Output base: A
Number: ACA
2762
Input base: 10
Output base: 10
Number:
Carriage return
$
结束语
总结
噢!本教程确实涵盖了许多内容,带您快速浏览了基本的 Shell 编程概念 。在学习本教程的过程中,您了解了有关 Shell 编程的许多核心概念:连续循环、内联输入、读取键盘输入、进制转换及 Subshell 执行 。您还了解到 Shell 代码片段如何能够作为单命令行程序直接从 Shell 提示符上运行,以及如何将它们放在同一个文件中作为可执行脚本 。您可以从中学习一些最重要的脚本编程概念 。您如果能综合运用在本教程以及本系列教程的前面部分学到的知识,那么您已成功地迈上 UNIX 专家之路 。

推荐阅读