搜索模式并使用该模式第一次出现的位置更新记录

搜索模式并使用该模式第一次出现的位置更新记录

我有一个文件,其中包含带有标识符的记录。对于每个标识符,可能有多个记录。我想搜索具有相同标识符的所有记录,并在这些记录中查找特定模式(特定位置的 Y);如果该模式存在,我想用该模式更新该指标的第一条记录。我怎样才能最好地通过脚本来实现这一点? (Unix 或 Windows)。该文件已按标识符排序。
这是我想要完成的示例:

identifier1aaaNbbb  
identifier1cccNddd  
identifier1eeeYfff

如果标识符 1 的记录之一在位置 14 处有“Y”,则将该“Y”写入标识符 1 记录的第一次出现,即

identifier1aaaYbbb  
identifier1cccNddd  
identifier1eeeYfff

我不确定哪种工具 ( awkgrepsed) 最适合此操作?知道如何解决吗?

答案1

使用awk并读取输入文件两次来处理它。

这是假设您的标识符长度为 11 个字符,并且您正在查找Y第 15 个字符的行(如您的示例中所示)。如果标识符不总是 11 个字符长,则需要修改脚本的第一行。

第一遍:将每个标识符的第一条记录保存在数组中,如果Y找到记录,则修改此数组元素。

第二遍:用保存的和可能修改的数组值替换每个标识符的第一条记录的行,并打印该行。

awk '{
  ident=substr($0,0,11)  # get identifier
  if (NR==FNR){          # first pass
    if (!(ident in a)){  # if identifier is not present in array
      a[ident]=$0        # save current line in array
    }
    if (substr($0,15,1) == "Y"){  # if `Y` is found in current line
                                  # replace character with `Y` in array value
      a[ident]=substr(a[ident],0,14)"Y"substr(a[ident],16)
    }
  }
  else {               # second pass
    if (ident in a){   # if identifier is present in array
      $0=a[ident]      # replace current line
      delete a[ident]  # delete array element
    }
    print              # print current line
  }
}' file file

答案2

不是优雅的。仅供参考。

首先,识别所有identifier1记录
command1:grep '^identifier1' my_file_name
这将打印仅有的带有您选择的标签的行。稍后,您可以查找具有不同标识符的记录。

有了这些记录后,您就可以搜索只是第 14 列,使用 cut 命令:
command2:_command1_ | cut -c14
为了清楚起见,我在命令上使用了速记符号。希望它们对你有意义。
command2 使用 cut 命令仅打印第 14 个字符(-c对于“字符”)。

然后您可以在此输出中查找“Y”。
command3:_command2_ | grep -q Y -q 表示“安静”——不输出任何内容。
rc=$? 注意:有人说你不需要 rc,只需查看 $?。你的来电。此时,如果$rc(或$?)为0,则grep至少找到一个大写Y。否则为1(也可能是其他数字,表示错误)。

让我们这样编码:注意:如果您在和 之间
if [ $rc -ne 0 ] then echo "No Ys found" exit fi
放置任何命令,则必须使用否则 $?很好。 要将 N 的所有指示符更改为 Y,您可以运行以下 sed 命令: grep -q Yifrc=$?

sed -i "/^identifier1/ s/\(………….\).\(.*\)/\1Y\2/" my_file_name

表示-i文件的就地编辑。
/^identifier1/只匹配以以下开头的行指示符1
意味着s搜索和替换。 SearchFor 在 / 之后 Replace With 在下一个斜线之后。
搜索:您想要第 14 个字符。有一种优雅的方法可以做到这一点sed。我将把这个留给其他人来解释。简单的答案是:
-点-表示任何字符。所以 13 个点表示匹配前 13 个字符。因为我们希望保持它们完好无损,所以我们将它们存储在桶中。 is it ( and ) – 转义括号。所以:
/\( 13 dots \) . \( dot * \)假设抓取该行的前 13 个字符并将它们存储在 Bucket #1 中。点表示匹配 1 个字符。点星表示“匹配 0 个或多个字符”——即其他所有字符——并将其存储在 Bucket #2 中。

现在进行替换:
/\1Y\2/表示用 Bucket #1 的内容替换该行,然后是 Y,然后是 Bucket #2。

有一种方法可以清理这个问题并提高效率。我面前没有 Linux 机器,而且一时记不起如何操作。
当其他一些FAB人们把它发布出来,你现在应该能够理解它了。

相关内容