首页 > 解决方案 > 仅用 awk 替换 sed/tail/grep

问题描述

我有以下任务要完成。我一起使用 awk/sed/tail/grep 完成了它,但我相信只使用 awk是可行的- 因此我请求您的帮助:

什么是 awk 语法 -

  1. 从文件 A 中获取最后一行(csv 格式)

LAST=$(tail -n1 A)

  1. 检查文件 A 中的行是否存在于文件 B 中(也存在 csv),如果是...

NO=$(grep -nw "$LAST" B|awk -F: {print $1})'

  1. 检查文件 B 中是否有更新的行,如果是...
BELOW=$(expr $NO + 1)
if awk "NR==$BELOW" B; then
  1. 删除文件 B 中从 $NO 到第二行的所有内容

sed -i "2,$NO d" B; fi

非常感谢您的帮助 - 非常感谢!

标签: linuxawk

解决方案


像这样的东西可能会起作用:

awk 'FNR == NR { last = $0; next }
     !newer && $0 == last { newer = 1; next }
     newer || FNR == 1' A B

只要我们在第一个文件中,基本上FNR == NR { last = $0; next }就设置为每一行,所以最后它将是第一个文件的最后一行。last

在第二个文件中,如果我们不在较新的行中并且行 equals last,则下一行比第一个文件中的新:!newer && $0 == last { newer = 1; next }.

当我们在第一行或第二个文件的新行时,它会被打印出来:newer || FNR == 1.

这与原来的不同之处在于它打印出 B 的较新行,而不是在原地修改 B。当然,您可以将输出重定向到 shell 中的临时文件,然后如果它包含多行,则将其移动到 B 上。或者让 awk 返回一个退出状态并使用它,例如:

tmpf=`mktemp B'.XXXXXX'`
awk 'FNR == NR { last = $0; next }
!newer && $0 == last { newer = NR; next }
newer || FNR == 1 { print }
END { exit (!newer || NR == newer) }' \
A B >"$tmpf" && mv "$tmpf" B || rm -f "$tmpf"

诚然,不再完全使用 Awk,但我会说在实践中足够接近和更好。


推荐阅读