使用gnu-parallel加速grep和awk

时间:2014-11-18 10:33:37

标签: bash awk grep gnu-parallel

我希望使用优秀的gnu-parallel工具加速两行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/${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}
 [...]

我的想法是,我只是以错误的方式管道并行命令......

3 个答案:

答案 0 :(得分:2)

一些想法:

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
  • 使用while read ... done < file代替cat blabla。
  • 不要使用echo ${FILENAME##*/}来分配变量,只需执行FILE_BASENAME=${FILENAME##*/}
  • 解释您希望使用grep/awk对完成什么,因为它可能会得到改进。例如,以下表达式没有多大意义。

    awk '{if (gsub("t=|...|c=","")) print; else print}' ...
    

您想要执行以下任一操作:替换然后打印线,或者如果没有替换则打印原始线。您可以直接说gsub(); print,因为gsub()会更新$0(该行)的值,以防它匹配:

awk '{gsub("t=|...|c=",""); print}' ...

答案 1 :(得分:1)

由于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)并返回所做的替换次数。我已删除条件代码,因为您似乎要打印记录,是否进行了任何替换。

答案 2 :(得分:0)

当你有一个脚本为单个文件完成工作时,将它转换为GNU Parallel通常很简单:

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}
}