管道输出到具有多个输入的bash函数

管道输出到具有多个输入的bash函数,bash,awk,pipe,levenshtein-distance,Bash,Awk,Pipe,Levenshtein Distance,下面是我试图做的:我想使用bash测量两个字符串之间的距离。我找到了一个实现 现在,假设我有一些玩具数据如下: 1 The brown fox jumped The green fox jumped 0 The red fox jumped The green fox jumped 1 The gray fox jumped The green fox jumped 假设它存储在数据中。test 然后我通过一个简单的awk命令过滤掉以1开头的行,如下所示:

下面是我试图做的:我想使用bash测量两个字符串之间的距离。我找到了一个实现

现在,假设我有一些玩具数据如下:

1    The brown fox jumped    The green fox jumped
0    The red fox jumped    The green fox jumped
1    The gray fox jumped    The green fox jumped
假设它存储在
数据中。test

然后我通过一个简单的
awk
命令过滤掉以
1
开头的行,如下所示:

awk -F '\t' '{if ($1>0) print $2,t,$3}' data.test
这个简单命令的第一个输出将是:

The brown fox jumped    The green fox jumped
我现在想测量这两句话之间的距离,通过管道将此输出直接传输到此函数(从上面的链接提升):

函数levenshtein{
如果($#!=2));那么
echo“用法:$0 word1 word2”>&2
elif(${1}<${2}));然后
levenshtein“$2”“$1”
其他的
本地str1len=${1}
本地str2len=${2}
局部d
以美元表示的i(seq 0$((str1len+1)*(str2len+1));do
d[i]=0
完成
对于以美元为单位的i(seq 0$str1len);是否
d[i+0*str1len]=$i
完成
对于以美元表示的j(seq 0$str2len);是否
d[0+j*(标准长度+1)]=$j
完成
对于以美元表示的j(序号1$str2len);是否
对于以美元表示的i(seq 1$str1len);是否
[“${1:i-1:1}”=“${2:j-1:1}”]&本地成本=0 | |本地成本=1
del=$((d[(i-1)+str1 len*j]+1))
ins=$((d[i+str1len*(j-1)]+1))
alt=$((d[(i-1)+标准长度*(j-1)]+成本)
d[i+str1len*j]=$(echo-e“$del\n$ins\n$alt”| sort-n | head-1)
完成
完成
echo${d[str1len+str1len*(str2len)]}
fi
}
我知道你可以这样做,但我被两个需要传递的参数和我传递序列的事实所困扰

我尝试过使用不同版本的建议,主张抓住输入:

function levenshtein {
    # Grab input.
    declare input1=${1:-$(</dev/stdin)};
    declare input2=${2:-$(</dev/stdin)};
.
.
.
}
函数levenshtein{
#抓取输入。

declare input1=${1:-$(如果在使用
export-f Levenshtein
调用awk之前在bash中导出Levenshtein函数,则可以轻松地在awk中逐行调用该函数:
awk-F'\t'$1>0{system(“levenshtein\'2'\'3'\)}
您根本不需要
awk

while IFS=$'\t' read num first second; do
    [[ $num -gt 0 ]] || continue
    levenshtein "$first" "$second"
done < data.txt

我对切普纳的答案投了赞成票,但如果出于某种原因,你发现自己陷入了一个需要解决这个问题的境地,那也不难

# Awk script refactored slightly for aesthetics
pair=$(awk -F '\t' '$1>0 {print $2 "\t" $3}' data.test)
levenshtein "${pair%$'\t*'}" "${pair#$'*\t'}"
稍微打开包装

  • levenshtein
    的两个参数在双引号中
  • 每个参数由一个参数替换组成;
    • ${variable%pattern}
      生成
      变量的值
      ,并删除与
      模式匹配的任何后缀
    • ${variable#pattern}
      生成
      变量的值
      ,并删除与
      pattern
      匹配的任何前缀
    • 这两个变量都匹配最短的
      模式
      。如果字符串包含多个字段,则可能需要分别从值的前面或后面修剪最长的
      模式
      变量
  • $'\t'
    是一个C样式的字符串,其中包含一个选项卡
  • 模式
    在选项卡前面或后面还包含一个
    *
    ,用于删除选项卡之前或之后的所有内容,以便仅从选项卡分隔的字符串中获取第一个或第二个值

这是一种非常好且简洁的方法,谢谢。在awk中会快得多。一个快速的谷歌产品,以及其他。我可以像问题中演示的那样将内容导入awk版本吗?我看不到问题中演示了它,但是的,awk可以从管道或文件读取输入。哦,公平,我的意思是说“演示的意图”我的问题是,只是将输出管道化到一个函数。根据你关于速度的评论,你会推荐什么?我在bash中这样做,因为我认为它比python快得多,但这基本上是唯一的原因。还有其他更快的吗?(同样,回答很好)为什么你认为
bash
比Python快?
bash
旨在运行其他程序,而不是自己进行计算。好吧,用熊猫做这些事情,比如说,超过数十万个句子对(在我的例子中是几gb的数据)我的计算机将要崩溃,以前也曾崩溃过。我听到有人鼓吹用bash代替那样的大型操作。你可能内存不足;你不会崩溃,因为Python比
bash
慢。你要么误解了这些“人”的意思你在说,或者你在听一些被误导的人说。那么,我将有另一张熊猫通行证,谢谢
levenshtein () {
  if (( ${#1} < ${#2} )); then
    levenshtein "$2" "$1"
    return
  fi

  local str1len str2len cost m a b i j
  local -A d

  str1len=${#1}
  str2len=${#2}
  for ((i=0;i<=strlen1;i++)); do
    d[$i,0]=0
  done

  for ((j=0;j<=strlen2;j++)); do
    d[0,$j]=0
  done

  for ((j=1; j<=str2len; j++)); do
    for ((i=1; i<=str1len; i++)); do
      a=${1:i-1:1}
      b=${2:j-1:1}
      [ "$a" = "$b" ] && cost=0 || cost=1
      del=$(( $d[$((i-1)),$j] + 1 ))
      ins=$(( $d[$i,$((j-1))] + 1 ))
      alt=$(( $d[$((i-1)),$((j-1))] + cost ))

      # Compute the min without forking
      m=$del; ((ins < m)) && m=$ins; ((alt < m)) && m=$alt

      d[$i,$j]=$m
    done
  done
  echo ${d[$str1len,$str2len]}
} 
# Awk script refactored slightly for aesthetics
pair=$(awk -F '\t' '$1>0 {print $2 "\t" $3}' data.test)
levenshtein "${pair%$'\t*'}" "${pair#$'*\t'}"