Bash 脚本查找第二个列表中第一个出现的列表元素

Bash 脚本查找第二个列表中第一个出现的列表元素

我有一个数字列表(无重复),val_str="11 22 33"如果需要,可以将其存储为数组,例如:val_arr=(11 22 33)

我有第二个数字列表,这些数字来自制表符分隔文件中的字段。如果需要的话,我可以使用awk.以下是一些玩具数据:

echo -e "66\n55\n99\n33\n11\n88\n77\n22\n33" > list

val_arr我想找到第一个出现在 中的元素的值list。的某些元素可能val_arr不会出现在 中list。如果 的所有元素val_arr都出现在 中,则下面的代码有效list,但如果不是这种情况,则失败,例如 if val_arr=(11 44 22 33)

val_arr=(11 22 33)
echo -e "66\n55\n99\n33\n11\n88\n77\n22\n33" > list
pos_arr=()
for i in ${!val_arr[@]}; do
    list_pos=$(grep -nm 1 ${val_arr[$i]} list | cut -f1 -d:)
    pos_arr+=( ${list_pos} )
done

pos1=$(echo ${pos_arr[@]} | tr ' ' '\n' | awk 'NR==1 {min=$0} NR>1 && $1<min {min=$1; pos=NR} END {print pos}')
pos0=$(( pos1 - 1 ))
val=${val_arr[$pos0]}

在两者的情况下val_arr=(11 22 33)val_arr=(11 44 22 33)我希望脚本返回33

我的问题是:

  1. 有一个更好的方法吗?
  2. 有没有办法使此代码对缺失值具有鲁棒性(比将所有值附加到withval_arry的末尾更优雅)?listecho ${pos_arr[@]} | tr ' ' '\n' >> list

谢谢!

PS 感谢@Adrian Frühwirth 提供了awk上面的代码: https://stackoverflow.com/questions/16610162/bash-return-position-of-the-smallest-entry-in-an-array

答案1

val_arr变成 grep 模式或表达式列表怎么样

$ echo "${val_arr[@]/#/-e}"
-e11 -e44 -e22 -e33

并直接使用它?

$ grep -wFm1 "${val_arr[@]/#/-e}" list
33

答案2

我只需使用grep数组并将其转换为字符串:

#!/bin/bash
val_arr=(11 22 33)

grep_string=$(tr ' ' '|' <<<"${val_arr[@]}")

first_found=$(grep -wEm1 "$grep_string" list);
if [[ -z $first_found ]]; then
  echo "None of the numbers were found"
else
  echo "Found: $first_found"
fi

tr命令会将数组转换为由 分隔的元素列表|

$ grep_string=$(tr ' ' '|' <<<"${val_arr[@]}")
$ echo $grep_string 
11|22|33

然后可以将其传递给grep -E.使用的选项是:

  • -E:启用扩展正则表达式,以便我们可以用来|表示“OR”。
  • -w: 只匹配整个单词,因此3不匹配33。您也可以使用-x(匹配整行),具体取决于您的输入。
  • -m1:第一场比赛后停止。

如果您还需要文件中的位置,请添加-n,以便它也将打印行号。

相关内容