我们有一个在 RHEL Linux 中开发的自定义脚本(在 ksh 中)。 功能是 1)读取输入的ASCII文件 2) 使用 sed -i inplace 文件将“\”替换为“\\” 3)将历史文件载入内存 4) 将数据与当天进行比较 5) 生成净变化记录
在平台升级期间,我们必须在 AIX 7.1 上迁移此脚本,并且 用 bash 替换了 ksh,因为 typeset -A 在 ksh AIX 上不可用,sed -i 命令用 perl -pi -e 并且脚本的其余部分几乎相同。
我们观察到该脚本在 Linux 中处理了 1 小时(691 个文件),但在 AIX 中它花费了 7 个多小时。
我们观察到对于一个输入文件,以下代码片段存在性能差异,Linux 代码在 1-2 秒内完成,而在 AIX 中需要 13-15 秒。由于每个文件的这种性能差异,对于 691 个文件,脚本需要 7 个小时才能完成。
能否请您帮助我了解我们是否可以调整此脚本以在 AIX 上获得更好的性能。任何指针都会非常有帮助。 预先感谢您的帮助!
在下面添加测试结果以获得更精确的问题
Linux 测试脚本:
#!/bin/sh
export LANG="C"
echo `date`
typeset -A Archive_Lines
if [ -f "8249cii1.ASC" ]
then
echo `date` Starting sed
sed -i 's/\\/\\\\/g' 1577cii1.ASC
echo `date` Ending sed
while read line; do
if [[ "${#line}" == "401" ]]
then
Archive_Lines["${line:0:19}""${line:27}"]="${line:27:10}"
else
echo ${#line}
fi
done < 1577cii1.ASC
echo `date` Starting sed
sed -i 's/\\\\/\\/g' 1577cii1.ASC
echo `date` Ending sed
fi
echo `date`
Linux 执行:
ksh read4.sh
Sun Nov 12 15:03:18 CST 2017
Sun Nov 12 15:03:18 CST 2017 Starting sed
Sun Nov 12 15:03:19 CST 2017 Ending sed
402
405
403
339
403
403
Sun Nov 12 15:03:22 CST 2017 Starting sed
Sun Nov 12 15:03:23 CST 2017 Ending sed
Sun Nov 12 15:03:23 CST 2017
AIX 测试脚本:
#!/usr/bin/bash
export LANG="C"
echo `date`
typeset -A Archive_Lines
if [ -f "1577cii1.ASC" ]
then
echo `date` Starting perl
perl -pi -e 's/\\/\\\\/g' 1577cii1.ASC
echo `date` Ending perl
while read line; do
if [[ "${#line}" == "401" ]]
then
Archive_Lines["${line:0:19}""${line:27}"]="${line:27:10}"
else
echo ${#line}
fi
done < 1577cii1.ASC
echo `date` Starting perl
perl -pi -e 's/\\\\/\\/g' 1577cii1.ASC
echo `date` Ending perl
fi
echo `date`
AIX 测试执行:
bash read_test.sh
Sun Nov 12 15:00:17 CST 2017
Sun Nov 12 15:00:17 CST 2017 Starting perl
Sun Nov 12 15:00:18 CST 2017 Ending perl
402
405
313
403
337
403
403
Sun Nov 12 15:01:29 CST 2017 Starting perl
Sun Nov 12 15:01:29 CST 2017 Ending perl
Sun Nov 12 15:01:29 CST 2017
将 Archive_Lines["${line:0:19}""${line:27}"]="${line:27:10}"替换为 echo"."
bash read_test.sh
Sun Nov 12 16:56:27 CST 2017
Sun Nov 12 16:56:27 CST 2017 Starting perl
Sun Nov 12 16:56:27 CST 2017 Ending perl
.
.
.
.
.
Sun Nov 12 16:56:42 CST 2017 Starting perl
Sun Nov 12 16:56:42 CST 2017 Ending perl
Sun Nov 12 16:56:42 CST 2017
使用 Archive_Lines["${line:0:19}""${line:27}"]="${line:27:10}"
bash read_test.sh
Sun Nov 12 16:59:52 CST 2017
Sun Nov 12 16:59:52 CST 2017 Starting perl
Sun Nov 12 16:59:52 CST 2017 Ending perl
402
405
313
403
337
403
403
Sun Nov 12 17:01:11 CST 2017 Starting perl
Sun Nov 12 17:01:11 CST 2017 Ending perl
Sun Nov 12 17:01:11 CST 2017
谢谢, 万西
最佳答案
正如 Walter 所建议的那样,看起来 bash
中的子字符串处理(可能还有长度测试)有一些性能问题。
可能有兴趣了解您使用其他解决方案获得的时间类型。
这是一个简单的 awk
解决方案,它应该做与原始 bash/substring 逻辑相同的事情(使用您当前的示例数据文件;没有行长度的输出!= 401):
awk 'length($0)==401 { print substr($0,1,20)substr($0,28)"|"substr($0,28,10) }' 1577cii1.ASC | \
while IFS="|" read idx val
do
Archive_Lines["${idx}"]="${val}"
done
length($0)==401
: 如果行长度是 401 那么 ...打印 ...."|"...
: 打印由管道 (|
) 分隔的输出/字段的 2 部分,其中字段是 ...substr($0,1,20)substr($0,28)
:相当于你的 ${line:0:19}${line:27}substr($0,28,10)
:相当于你的 ${line:27:10}- 此时每行长度为 401 的输出都像
string1|string2
同时 IFS="|"读取 idx val
:将输入拆分回 2 个变量 ...Archive_Lines["${idx}"]="${val}"
:使用 2 个变量作为数组索引/值对
注意:添加竖线 (|
) 作为字段分隔符是为了防止您的子字符串包含空格;当然,如果您的子字符串可以包含竖线 (|
),则替换为不会出现在您的子字符串中并且可以用作字段分隔符的其他字符。
目标是查看awk 的
内置长度/子字符串处理是否比bash 的
长度/子字符串处理更快...
关于linux - 在 AIX/bash 上以 bash 循环读取文件比在 Linux/ksh 中慢得多 - BLOCKSIZE?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47253048/