我有一个文件,其中包含带有标识符的记录。对于每个标识符,可能有多个记录。我想搜索具有相同标识符的所有记录,并在这些记录中查找特定模式(特定位置的 Y);如果该模式存在,我想用该模式更新该指标的第一条记录。我怎样才能最好地通过脚本来实现这一点? (Unix 或 Windows)。该文件已按标识符排序。
这是我想要完成的示例:
identifier1aaaNbbb
identifier1cccNddd
identifier1eeeYfff
如果标识符 1 的记录之一在位置 14 处有“Y”,则将该“Y”写入标识符 1 记录的第一次出现,即
identifier1aaaYbbb
identifier1cccNddd
identifier1eeeYfff
我不确定哪种工具 ( awk
、grep
、sed
) 最适合此操作?知道如何解决吗?
答案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 Y
if
rc=$?
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人们把它发布出来,你现在应该能够理解它了。