GNU 与自定义脚本并行进行字符串比较

GNU parallel with custom script doing string comparison

以下 script.sh 将字符串的一部分(来自 stdincat 一个 csv 文件)与定义的字符串进行比较,并以特定格式报告差异

#!/usr/bin/env bash

reference="ABCDEFG"
ref_transp=$(echo "$reference" | sed -e 's/\(.\)/\n/g')
while read line; do
  line_transp=$(echo "$line" | cut -d',' -f2 | sed -e 's/\(.\)/\n/g')
  output=$(paste -d ' ' <(echo "$ref_transp") <(echo "$line_transp") | grep -vnP '([A-Z]) ' | sed -E 's/([0-9][0-9]*):([A-Z]) ([A-Z]*)//' | grep '^[A-Z][0-9][0-9]*[A-Z*]$')
  echo "$(echo ${line:0:35}, $output)"
done < "${1:-/dev/stdin}"

它打算在格式非常大​​的文件中的多行上执行

XYZ,ABMDEFG

当我在管道中使用它时效果很好:

cat large_file | ./find_something.sh

但是,当我尝试将它与 parallel 一起使用时,出现此错误:

$  cat large_file | parallel ./find_something.sh
./find_something.sh: line 9: XYZ, ABMDEFG : No such file or directory

这是什么原因造成的?如果我之后想将输出重定向到单个文件,parallel 是否应该为这样的事情工作?

不太重要的旁注:我为我的字符串比较方法感到自豪,但如果有人有更快的方法来比较 ABCDEFGXYZ,ABMDEFG 以获得 XYZ,C3M我也很高兴听到这个消息。

编辑:

我应该说,我还想保留输出中每一行的顺序,与输入相对应。可以使用并行吗?

您的脚本接受来自文件的输入(默认为标准输入),而 parallel 将输入作为参数传递,而不是通过标准输入。从这个意义上说,parallel 更接近于 xargs

据推测,您希望 large_file 中的每一行作为一个单元处理,可能是并行处理。

这意味着您需要您的脚本一次只处理这样的一行,并让 parallel 多次调用您的脚本,每行一次。

所以你的脚本应该是这样的:

#!/usr/bin/env bash

reference="ABCDEFG"
ref_transp=$(echo "$reference" | sed -e 's/\(.\)/\n/g')
line=""
line_transp=$(echo "$line" | cut -d',' -f2 | sed -e 's/\(.\)/\n/g')
output=$(paste -d ' ' <(echo "$ref_transp") <(echo "$line_transp") | grep -vnP '([A-Z]) ' | sed -E 's/([0-9][0-9]*):([A-Z]) ([A-Z]*)//' | grep '^[A-Z][0-9][0-9]*[A-Z*]$')
echo "$(echo ${line:0:35}, $output)"

然后你可以重定向到一个文件如下:

cat large_file | parallel ./find_something.sh > output_file

-k保持顺序。

#!/usr/bin/env bash

doit() {    
    reference="ABCDEFG"
    ref_transp=$(echo "$reference" | sed -e 's/\(.\)/\n/g')
    while read line; do
      line_transp=$(echo "$line" | cut -d',' -f2 | sed -e 's/\(.\)/\n/g')
      output=$(paste -d ' ' <(echo "$ref_transp") <(echo "$line_transp") | grep -vnP '([A-Z]) ' | sed -E 's/([0-9][0-9]*):([A-Z]) ([A-Z]*)//' | grep '^[A-Z][0-9][0-9]*[A-Z*]$')
      echo "$(echo ${line:0:35}, $output)"
    done
}
export -f doit

cat large_file | parallel --pipe -k doit
#or
parallel --pipepart -a large_file --block -10 -k doit