【问题标题】:GNU parallel with custom script doing string comparisonGNU 与自定义脚本并行进行字符串比较
【发布时间】:2019-12-07 23:28:57
【问题描述】:

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

#!/usr/bin/env bash

reference="ABCDEFG"
ref_transp=$(echo "$reference" | sed -e 's/\(.\)/\1\n/g')
while read line; do
  line_transp=$(echo "$line" | cut -d',' -f2 | sed -e 's/\(.\)/\1\n/g')
  output=$(paste -d ' ' <(echo "$ref_transp") <(echo "$line_transp") | grep -vnP '([A-Z]) \1' | sed -E 's/([0-9][0-9]*):([A-Z]) ([A-Z]*)/\2\1\3/' | 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 我很高兴听到,也是。

编辑:

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

【问题讨论】:

  • 请编辑您的 Q 以显示来自示例输入的所需输出。还请包括reference 的示例数据和您正在使用的任何其他静态数据。祝你好运。
  • 考虑在顶部使用“set -x”来运行您的脚本。您将获得有助于调试问题的信息。另外,请将带有 XYZ、ABMDEFG 的行(和其他一些好的行)发布,以便可以复制
  • 据我所知,您每行运行大约 10 个外部进程,cutsedgreppaste 等等。大概您想使用 GNU Parallel 来加快速度。我不禁想到你会做得更好,以显示输入和所需的输出,并在一个 awk 脚本中完成所有工作。

标签: bash parallel-processing string-comparison large-files


【解决方案1】:

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

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

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

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

#!/usr/bin/env bash

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

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

cat large_file | parallel ./find_something.sh > output_file

【讨论】:

  • 这是我原来问题的正确解决方案。但是,它弄乱了行的顺序。有什么办法可以防止这种情况发生,或者这是与并行不相容的愿望吗?
  • 如果你并行运行,你就会失去顺序。如果您需要保留顺序,我建议使用cat -n large_file | parallel ./find_something.sh | sort -n | cut -d' ' -f2- 之类的东西,并让find_something.sh 只写第一个参数,因为它后跟一个空格,然后是实际输出。要了解它是如何工作的,请想象 find_something.sh 只是 tac | xargs -L 1 echo,然后运行例如cat -n /etc/passwd | tac | xargs -L 1 echo | sort -n | cut -d' ' -f2-
【解决方案2】:

-k 保持订单。

#!/usr/bin/env bash

doit() {    
    reference="ABCDEFG"
    ref_transp=$(echo "$reference" | sed -e 's/\(.\)/\1\n/g')
    while read line; do
      line_transp=$(echo "$line" | cut -d',' -f2 | sed -e 's/\(.\)/\1\n/g')
      output=$(paste -d ' ' <(echo "$ref_transp") <(echo "$line_transp") | grep -vnP '([A-Z]) \1' | sed -E 's/([0-9][0-9]*):([A-Z]) ([A-Z]*)/\2\1\3/' | 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

【讨论】:

  • 不知何故它以这种方式给了我空字符串,但是感谢您将我指向 --pipe 选项,这似乎也有效
  • 我已经在包含 XYZ,ABMDEFG 的 large_file 上对其进行了测试,它给出了相同的输出,所以我很困惑为什么你会得到空字符串。保持与输入相同的顺序很容易:使用-k
猜你喜欢
  • 2021-03-08
  • 2014-12-14
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
  • 2012-10-06
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多