Bash 使用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

我希望使用伟大的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/${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}
}