016.其他命令

1、多个文件的重命名与移动

移动或重命名多个文件是我们经常会碰到的一项工作。系统管理员经常需要将有相同前缀或相同类型的文件移动到新的目录中。从数码相机中下载的照片可能需要重命名并保存。音乐、视频和E-mail也得定期重新整理。

下面的脚本利用find查找PNG和JPEG文件,然后使用##操作符和mv将查找到的文件重命名为image-1.EXT、image-2.EXT等。注意,脚本并不会修改文件的扩展名:

#!/bin/bash
#文件名:rename.sh
#用途:重命名.jpg和.png文件
count=1;
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
do
	new=image-$count.${img##*.}
	echo "Renaming $img to $new"
	mv "$img" "$new"
	let count++
done
  • 使用了for循环迭代所有扩展名为.jpg或.png的文件。
  • 使用find命令展开搜索,选项-o用于指定多个-iname选项,后者用于进行大小写无关的匹配。选项-maxdepth 1仅搜索当前目录,不涉及其中的子目录。
  • 为了跟踪图像编号,我们将变量count初始化为1。
  • 接下来用mv命令重命名文件。新的文件名通过${img##*.}来构造,它能够从当前处理的文件名中解析出扩展名。
  • let count++用来在每次循环中递增文件编号。

2、拼写检查与词典操作

大多数Linux发行版都含有一份词典文件。然而,我发现几乎没人在意过这个文件,拼写错误仍是满天飞。还有一个叫作aspell的命令行实用工具,其作用是进行拼写检查。

目录/usr/share/dict/中包含了一些词典文件。所谓“词典文件”就是包含了单词列表的文本文件。我们可以利用它来检查某个单词是否在词典之中。

#!/bin/bash
#文件名:checkword.sh
word=$1
grep "^$1$" /usr/share/dict/british-english -q
if [ $? -eq 0 ]; then
	echo $word is a dictionary word;
else
	echo $word is not a dictionary word;
fi
  • 在grep中,^标记着单词的开始,$标记着单词的结束,-q选项 禁止grep产生任何输出。

作为另一种选择,我们也可以用拼写检查命令aspell来核查某个单词是否在词典中:

#!/bin/bash
#文件名:aspellcheck.sh
word=$1

output=`echo \"$word\" | aspell list`

if [ -z $output ]; then
	echo $word is a dictionary word;
else
	echo $word is not a dictionary word;
fi
  • 当给定的输入不是一个词典单词时,aspell list命令会生成输出,否则不产生任何输出。-z用于确认$output是否为空。
3、交互输入自动化

Linux也支持很多交互式应用程序,如passwd和ssh。

我们可以创建自己的交互式shell脚本。对于普通用户而言,相较于记忆命令行参数及其正确的顺序,同一系列提示信息打交道要更容易。

# 观察交互式输入的顺序。参照上面的代码,我们可以将涉及的步骤描述如下:
notes[Return]docx[Return]

# 输入notes,按回车键,然后输入docx,再按回车键。
"notes\ndocx\n"
  • 按下回车键时会发送\n。添加\n后,就生成了发送给stdin的字符串。
  • 通过发送与用户输入等效的字符串,我们就可以实现在交互过程中自动发送输入。

先写一个读取交互式输入的脚本,然后用这个脚本做自动化演示:

#!/bin/bash
# backup.sh
# 使用后缀备份文件。不备份以~开头的临时文件
read -p " What folder should be backed up: " folder
read -p " What type of files should be backed up: " suffix
find $folder -name "*.$suffix" -exec cp {} $BACKUP/$LOGNAME/$folder \;
echo "Backed up files from $folder to $BACKUP/$LOGNAME/$folder"

按照下面的方法向脚本发送自动输入:

# 输出:Backed up files from notes to /BackupDrive/MyName/notes
echo -e "notes\ndocx\n" | ./backup.sh
  • 像这样的交互式脚本自动化能够在开发和调试过程中节省大量输入。另外还可以确保每次测试都相同,不会出现由于输入错误导致的bug假象。
  • 用echo -e来生成输入序列。-e选项表明echo会解释转义序列。

如果输入内容比较多,可以用单独的输入文件结合重定向操作符来提供输入:

# 模拟 input.data 中有数据
echo -e "notes\ndocx\n" > input.data

# 从文件中导入交互式输入数据。
./backup.sh < input.data

echo命令和重定向可以实现交互式输入的自动化。但这种技术存在问题,因为输入内容没有经过验证,我们认定目标应用总是以相同的顺序接收数据。但如果程序要求的输入顺序不同,或是对某些输入内容不做要求,那就要出岔子了。

expect程序能够执行复杂的交互操作并适应目标应用的变化。该程序在世界范围内被广泛用于控制硬件测试、验证软件构建、查询路由器统计信息等。

用expect实现自动化(实验失败):

expect是一个和shell类似的解释器。它基于TCL语言。Linux发行版默认并不包含expect。需要用软件包管理器(apt-get或yum)手动进行安装。

expect有3个主要命令:

命令

描述

spawn

运行新的目标应用

expect

关注目标应用发送的模式

send

向目标应用发送字符串

下面的例子会先执行备份脚本,然后查找模式*folder*或*file*,以此确定备份脚本是否要求输入目录名或文件名并作出相应的回应。如果重写备份脚本,要求先输入备份文件类型,后输入备份目录,这个自动化脚本依然能够应对。

#!/bin/bash
# 文件名:automate_expect.tcl
spwan ./backup .sh
expect {
	"*folder*" {
		send "notes\n"
		exp_continue	
	}	
	"*type*" {
		send "docx\n"
		exp_continue
	}
}

# 运行脚本,运行失败,实验没做出来
./automate_expect.tcl
  • spawn命令的参数是需要自动化运行的应用程序及其参数。
  • expect命令接受一组模式以及匹配模式时要执行的操作。操作需要放入花括号中。
  • send命令是要发送的信息。和echo -n -e类似,send不会自动添加换行符,也能够理解转义字符。
4、利用并行进程加速命令执行

计算能力的持续攀升不仅仅是因为处理器有了更高的时钟频率,还因为多核的出现。这意味着单个物理处理器中包含了多个逻辑处理器。这就像是有了多台计算机一样。

但除非软件能够善加利用多核,否则它们毫无用武之地。例如,一个需要进行大量运算的程序可能仅运行在其中一个核心上,而其他的核心都处于闲置状态。如果想提高速度,软件必须留意并充分利用多核。

多文件效验:

以之前讲过的md5sum命令为例。由于需要执行复杂的运算,md5sum属于CPU密集型命令。如果多个文件需要生成校验和,我们可以使用下面的脚本来运行md5sum的多个实例:

#/bin/bash
# generate_checksums.sh
PIDARRAY=()
for file in File1.iso File2.iso
do
	md5sum $file &
	PIDARRAY+=("$!")
done
wait ${PIDARRAY[@]}
  • 我们利用了Bash的操作符&,它使得shell将命令置于后台并继续执行脚本。这意味着一旦循环结束,脚本就会退出,而md5sum进程仍在后台运行。
  • 为了避免这种情况,我们使用$!来获得进程的PID,在Bash中,$!保存着最近一个后台进程的PID。我们将这些PID放入数组,然后使用wait命令等待这些进程结束。
# 创建运行脚本需要的文件
touch File{1..2}.iso

# 运行脚本
./generate_checksums.sh 

  • 输出结果和下面命令的结果一样:md5sum File1.iso File2.iso
  • 但如果多个md5sum命令同时运行,配合多核处理器,你就会更快地获得运行结果(可以使用time命令来验证)

parallel 优化资源

对于少量任务,Bash的操作符&效果很好。如果你有数以百计的文件要计算校验和,那么脚本就会生成上百个进程,这有可能会强迫系统执行换页操作(swapping),拖慢执行速度。

并非所有系统都会安装GNU parallel命令,不过你仍可以使用软件包管理器来安装。该命令能够优化资源使用,避免系统超载。

parallel命令从stdin中读取文件列表,使用类似于find命令的-exec选项来处理这些文件。符号{}代表被处理的文件,符号{.}代表无后缀的文件名。

# 使用了Imagemagick的convert程序来为目录中的所有图像创建新的缩放版本:
ls *jpg | parallel convert {} -geometry 50x50 {.}Small.jp
5、检查目录以及其中的文件与子目录

我们处理得最多的一个问题就是查找放错地方的文件并整理凌乱的文件层次结构。我们之前讨论过的find命令以及循环能够帮助检查并报告目录及其内容。

有两种方法可以检查目录。一种方法是将目录层次以树状形式显示出来,另一种方法是生成目录下所有文件和子目录的汇总信息。

生成目录的树状视图:

有时候,如果文件系统以图形化形式呈现,会更容易形成直观的印象。

接下来的例子中综合运用了我们讲过的多种工具。其中使用find命令生成了当前目录下所有文件及子目录的列表。

-exec选项创建了一个子shell,在这个子shell中使用echo命令将文件名发送给tr命令的stdin。这里用到了两个tr命令。第一个tr删除了所有的字母数字字符、连字符(-)、下划线(_)和点号(.),只将路径中的斜线(/)传入第二个tr,后者将这些斜线全部转换成空格。最后,利用basename命令去掉文件名前的路径部分并将结果显示出来。

下面来查看目录/var/log的树状视图:

cd /var/log
find . -exec sh -c 'echo -n {} | tr -d "[:alnum:]_.\-" | tr "/" " "; basename {}' \;

生成文件及子目录的汇总信息:

我们可以结合find、echo和wc(下一章会详细讲解该命令)生成子目录列表以及其中的文件数量。

下面的命令可以获得当前目录下文件的汇总信息:

#!/bin/bash
# totalInfo.sh
for d in `find . -type d`;
do
	echo `find $d -type f | wc -l` files in $d;
done

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值