我使用 shell 脚本、awk 脚本和 find 命令的组合对数百个文件执行多次文本替换。文件大小在几百字节到 20 千字节之间。
我正在寻找一种方法来加快这个脚本的速度。
我正在使用 cygwin。
shell脚本
#!/bin/bash
if [ $# = 0 ]; then
echo "Argument expected"
exit 1
fi
while [ $# -ge 1 ]
do
if [ ! -f $1 ]; then
echo "No such file as $1"
exit 1
fi
awk -f ~/scripts/parse.awk $1 > ${1}.$$
if [ $? != 0 ]; then
echo "Something went wrong with the script"
rm ${1}.$$
exit 1
fi
mv ${1}.$$ $1
shift
done
awk 脚本(简化)-
#! /usr/bin/awk -f
/HHH.Web/{
if ( index($0,"Email") == 0) {
sub(/HHH.Web/,"HHH.Web.Email");
}
printf("%s\r\n",$0);
next;
}
命令行
find . -type f | xargs ~/scripts/run_parser.sh
答案1
1) 错误处理中存在错误。如果您通过单个 xargs 传递一组文件,并且一个文件崩溃,则其他后续文件都不会得到处理。例如,如果
~/scripts/run_parser.sh file1 file2 file3 file4
运行,并且 file2 在 awk 上崩溃,file1 运行,但 file2、file3 和 file4 都不会运行。我建议使用continue
而exit 1
不是 。
2) 您使用的是 Cygwin,由于模拟,速度会有点慢,这是没办法的。使用相同的工具,在 Linux 上速度会更快。
3)如果你能破解一些 perl,我建议你看看perl -p -i
可以。Perl 语法并不比 awk 复杂多少,并且您只需要一个 perl 实例,而不需要多个 awk 实例。
除非速度非常非常慢,否则我可能会将其归咎于模拟问题。除了 perl -p hack 可以克服 awk 的一些额外 fork/execs 之外,我认为没有什么灵丹妙药。
答案2
这将在不到 10 秒的时间内递归遍历我的所有数百个文件。以前,这需要 15 分钟。
find . -type f | xargs awk -f ~/scripts/awkv2/parse.awk
awk 脚本(简化)-
/HHH.Web/{
if ( index($0,"Email") == 0) {
sub(/HHH.Web/,"HHH.Web.Email");
}
printf("%s\r\n",$0); > FILENAME
next;
}
但,如果输入文件大于 64kb,则输出文件将被截断为大约 64kb。
知道原因吗?
答案3
这是读取文件的缓冲区大小,更重要的是,你正在覆盖原始的文件名。一个解决方案是使用
outFile= FILENAME ".fix"
printf("%s\r\n",$0); > outFile
并有单独的通行证
mv ${fileName}.fix ${fileName}
在 bash 中
我也同意 Rich 的观点,Cygwin 的仿真导致它运行速度变慢。除了 Linux,根据您所在组织对非 Gnu 开源软件的容忍度,您可以尝试 David Korn 的 UWIN(适用于 Windows 的 Unix),网址为http://www2.research.att.com/sw/tools/uwin/ 另请参阅http://en.wikipedia.org/wiki/UWIN。
祝你好运