Bash 使用gnu并行加速grep和awk
我希望使用伟大的gnu并行工具加速两行grep和awk代码,但使用简单的语法,它会崩溃或无限循环。非常感谢您的帮助 正常代码:Bash 使用gnu并行加速grep和awk,bash,awk,grep,gnu-parallel,Bash,Awk,Grep,Gnu Parallel,我希望使用伟大的gnu并行工具加速两行grep和awk代码,但使用简单的语法,它会崩溃或无限循环。非常感谢您的帮助 正常代码: for FILENAME in `cat FileList.tmp` do echo "Bearbeite $FILENAME ..." FILE_BASENAME=`echo ${FILENAME##*/}` grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} > ${INPUT}/cleaned/${FI
for FILENAME in `cat FileList.tmp`
do
echo "Bearbeite $FILENAME ..."
FILE_BASENAME=`echo ${FILENAME##*/}`
grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} > ${INPUT}/cleaned/${FILE_BASENAME}.tmp
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' \
${INPUT}/cleaned/${FILE_BASENAME}.tmp > ${INPUT}/cleaned/${FILE_BASENAME}
rm -f ${INPUT}/cleaned/${FILE_BASENAME}.tmp
done
并行尝试:
[...]
parallel -j100 --pipe grep -v "^t=[0-9]*.[0-9]*\&\-$" | awk '{s = s + $1} END {print s, s/NR}' ${FILENAME} > ${INPUT}/cleaned/${FILE_BASENAME}.tmp
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' \
${INPUT}/cleaned/${FILE_BASENAME}.tmp > ${INPUT}/cleaned/${FILE_BASENAME}
[...]
我的想法是,我只是用错误的方式传输并行命令…一些想法:
while IFS= read -r FILENAME
do
echo "Bearbeite $FILENAME ..."
FILE_BASENAME=${FILENAME##*/} # no need to echo
grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} > ${INPUT}/cleaned/${FILE_BASENAME}.tmp
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' \
${INPUT}/cleaned/${FILE_BASENAME}.tmp > ${INPUT}/cleaned/${FILE_BASENAME}
rm -f ${INPUT}/cleaned/${FILE_BASENAME}.tmp
done < FileList.tmp
您希望执行以下任一操作:替换然后打印行,或者如果未进行替换,则打印原始行。您可以直接说gsub();打印
,因为gsub()
会更新$0(行)的值,以防其匹配:
awk '{gsub("t=|...|c=",""); print}' ...
由于fedorqui已经对您的循环结构提出了一些观点,因此我将重点介绍如何结合grep和awk部分:
awk '!(/^t=[0-9]*.[0-9]*\&\-$/) {
gsub(/(t|r|i|d|ip|ua|uc|um|ud|pc|la|lo|do|dm|c)=/,""); print }' input > output
当模式不匹配时(与grep-v
相同),执行替换并打印结果。其他行将不会打印
在awk中,gsub
修改目标(默认情况下,整个记录,$0
)并返回所做替换的数量。我删除了条件代码,因为无论是否进行了任何替换,您似乎都想打印记录。当您有一个脚本为单个文件执行任务时,将其转换为GNU并行通常非常简单:
bearbeite() {
FILENAME=$1
echo "Bearbeite $FILENAME ..."
FILE_BASENAME=`echo ${FILENAME##*/}`
grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} > ${INPUT}/cleaned/${FILE_BASENAME}.tmp
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' \
${INPUT}/cleaned/${FILE_BASENAME}.tmp > ${INPUT}/cleaned/${FILE_BASENAME}
rm -f ${INPUT}/cleaned/${FILE_BASENAME}.tmp
}
export -f bearbeite
parallel bearbeite :::: FileList.tmp
# or:
cat FileList.tmp | parallel bearbeite
为了避免使用临时文件,应该这样做:
bearbeite() {
FILENAME=$1
echo "Bearbeite $FILENAME ..."
FILE_BASENAME=`echo ${FILENAME##*/}`
grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} |
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' > ${INPUT}/cleaned/${FILE_BASENAME}
}
我认为最好的加速方法是避免写入中间文件,并将grep和awk命令合并到一个awk命令中。此外,如果瓶颈是I/O限制的,那么添加并行性根本不会加快速度(除非您可以具体地并行化I/O,例如将输入分解成更小的块,并在单独的过程中处理每个块;但除非您经常这样做和/或大规模地这样做,否则这几乎不值得在这里付出努力)。虽然过去是这样,但现在已经不是这样了:如果我并行运行10个作业,我使用的RAID速度会快6倍。如果我并行运行更少或更多作业,RAID速度会慢一些。对于SSD磁盘,情况更糟。因此,唯一仍然有效的建议是:衡量哪一个更适合你。grep
命令应该删除行如果是空的,则仅保留与正则表达式匹配的文件。^t=[0-9].[0-9]*\&-$
awk
应在命令后用空字符“”替换t=| r=blablabla。修改应放在新文件中
bearbeite() {
FILENAME=$1
echo "Bearbeite $FILENAME ..."
FILE_BASENAME=`echo ${FILENAME##*/}`
grep -v "^t=[0-9]*.[0-9]*\&\-$" ${FILENAME} |
awk '{ if (gsub("t=|r=|i=|d=|ip=|ua=|uc=|um=|ud=|pc=|la=|lo=|do=|dm=|c=","")) print; else print}' > ${INPUT}/cleaned/${FILE_BASENAME}
}