【问题标题】:grep multi column, in order or awk better?grep 多列,顺序好还是awk好?
【发布时间】:2014-09-08 02:03:50
【问题描述】:

Linux Debian 测试 64。

我希望 grep 或 awk 以下内容...

ExifListAll = (下)

DSCF3566.JPG    2014-07-21 12:54:32 On  1
DSCF3566.RAF    2014-07-21 12:54:32 On  1
DSCF3567.JPG    2014-07-21 12:54:33 On  2
DSCF3567.RAF    2014-07-21 12:54:33 On  2
DSCF3568.JPG    2014-07-21 12:54:33 On  3
DSCF3568.RAF    2014-07-21 12:54:33 On  3
DSCF3569.JPG    2014-07-21 12:54:34 Off 0

我将使用第 3 列时间 12:54:33 开始,搜索前 1 秒和后 1 秒, 第 4 列 = “开启”,第 5 列 = 1、2 或 3

到目前为止我已经尝试过了;

echo "$ExifListAll" | grep -E '2014-07-21.*12:45:3[3-4].*On.*[1-3]'

我可以更有效地使用 awk 1 班轮吗?

我这样做对吗?

echo "$ExifListAll" | awk '$4 == "On" && $5~/1/,$5~/3/'

谢谢。

【问题讨论】:

  • 你能提供你想要的输出吗?
  • 不要在 awk 中使用范围表达式。它们使琐碎的任务变得非常简单,而稍微有趣的任务需要完全重写。使用/start/{f=1} f; /end/{f=0} 而不是/start/,/end/
  • @qwwqwwq。如果上述任何一项用于启动所需的输出,将使用 1 秒前、1 秒后(第 3 列)搜索上述列表,然后确保第 4 列为“开”。如果使用 DSCF3567.JPG,然后它将找到上面的所有项目(第 1-6 行)。
  • @Ed Morton。你会如何改变以采纳你的建议?例如回声“$ExifListAll”| awk '$4 == "开" && $5~/1/,$5~/3/'
  • 这取决于您认为该声明的含义,但我猜可能是awk '$5~/1/{f=1} f && ($4=="On"); $5~/3/{f=0}'

标签: bash awk grep


【解决方案1】:

您不能使用范围或标志来检索多个匹配 /end/ 块的行。对于 awk 更通用的解决方案,您可以将时间转换为纪元时间,然后设置比较:

mydatetime="2014-07-21 12:54:33"
awk -v expected_time=$(date -d"$mydatetime" +%s) '
  { t = $2" "$3; gsub(/[:-]/," ",t); t1 = mktime(t) }
  t1 >= expected_time-1 && t1 <= expected_time+1 && $4 =="On" && $5 ~ /^[123]$/
' file.txt

注意:

  1. 第 1 行:使用 -v expected_time=$(...) 将 expected_time 设置为纪元时间戳
  2. 将每条记录的 entrytime ($2" "$3) 转换为 "YYYY mm dd HH MM SS" 格式,然后输入 mktime() 以使用 awk 生成 epoch 时间戳。
  3. 比较时间并确保 $4 为“开启”且 $5 为 1、2 或 3。

如果您确切地知道您提到的 expected_time,那么只需使用您的 grep 行,比 awk 更简单、更快。

grep -E '2014-07-21.*12:54:3[2-4].*On.*[1-3]' file.txt

【讨论】:

  • 谢谢。如果我想使用 grep,我如何从任何时间作为起点在“秒”时间执行 -1 秒和 +1 秒的数学运算?
  • 恐怕 grep 不是做数学的正确工具。您可能可以在 BASH 中计算它们,然后将它们输入到正则表达式中以交替进行 grep,即 ($time1|$time2|$time3)。
【解决方案2】:

grep 可以很好地满足您的目的。您只是对语法有挑战。首先,使用模式\s* 来匹配字段之间的零个或多个空格更容易。您正在使用.*(因为正则表达式是贪婪的)会将每个字符匹配到行尾。此外,字符类是指其中包含的字符。 IE。要匹配 1、2 或 3,请使用 [123]。通过这些更改,以下内容可以实现您的意图:

echo "$ExifListAll" | grep -E "2014-07-21\s*12:54:3[34]\s*On\s*[123]"

输出:

$ cat grepdat.dat | grep -E "2014-07-21\s*12:54:3[34]\s*On\s*[123]"
DSCF3567.JPG    2014-07-21 12:54:33 On  2
DSCF3567.RAF    2014-07-21 12:54:33 On  2
DSCF3568.JPG    2014-07-21 12:54:33 On  3
DSCF3568.RAF    2014-07-21 12:54:33 On  3

这不是您期望的输出吗? 12:54:34 有Off0,我从您的问题中将其解释为不需要。如果您希望状态 On/Off regardless, and included the0` 对应于 12:54:34 Off 0,则使用:

echo "$ExifListAll" | grep -E "2014-07-21\s*12:54:3[34]\s*(On|Off)\s*[0123]"

输出:

$ cat grepdat.dat | grep -E "2014-07-21\s*12:54:3[34]\s*(On|Off)\s*[0123]"
DSCF3567.JPG    2014-07-21 12:54:33 On  2
DSCF3567.RAF    2014-07-21 12:54:33 On  2
DSCF3568.JPG    2014-07-21 12:54:33 On  3
DSCF3568.RAF    2014-07-21 12:54:33 On  3
DSCF3569.JPG    2014-07-21 12:54:34 Off 0

需要第 1-6 行的评论:

cat grepdat.dat | grep -E "2014-07-21\s*12:54:3[234]\s*On\s*[123]"

输出

$ cat grepdat.dat | grep -E "2014-07-21\s*12:54:3[234]\s*On\s*[123]"
DSCF3566.JPG    2014-07-21 12:54:32 On  1
DSCF3566.RAF    2014-07-21 12:54:32 On  1
DSCF3567.JPG    2014-07-21 12:54:33 On  2
DSCF3567.RAF    2014-07-21 12:54:33 On  2
DSCF3568.JPG    2014-07-21 12:54:33 On  3
DSCF3568.RAF    2014-07-21 12:54:33 On  3

【讨论】:

  • 谢谢您,不幸的是您的代码结果错过了“2014-07-21 12:54:34”...不知道为什么。是否可以通过加 1 和减 1 对时间字段的最后 2 个数字进行数学运算以实现 12:54:33、12:54:34、12:54:35 ?再次感谢。
  • 我发布的第一条消息中的第 1-6 行是所需的输出,如果使用任何时间作为起点。谢谢你的时间。你是对的,第 5 列 '0' 被省略了。如果时间字段中的最后 2 位数字未知,但需要包含 +1 和 -1 秒,我正在努力如何完成这项工作。
  • 真的吗?这是一个简单的调整。现在看看答案。考虑一下表达式的每个部分的作用...您可以通过简单地将2 添加到第一个字符类使其成为[234] 来调整它。花点时间熟悉答案,不要仅仅用它来解决问题,以免失去预期的学习。
【解决方案3】:

谢谢大家的建议。

我使用了另一种更直接的方法,即“exiftool” 它从图像中读取所有元数据。

我选择了目录中的任何图像,然后给出前一秒和下一秒。 我还不确定如何替换提供的信息,但我会在您的帮助下解决。

DateTimeOrigFirst="$(exiftool -T -d '%F %T' -DateTimeOriginal DSCF3567.RAF)"
DateTimeOrig1SecMinus="$(exiftool -T -globalTimeShift "-0:0:0 0:0:1" -d '%F %T' -DateTimeOriginal DSCF3567.RAF)"
DateTimeOrig1SecPlus="$(exiftool -T -globalTimeShift "+0:0:0 0:0:1" -d '%F %T' -DateTimeOriginal DSCF3567.RAF)"

然后我可以在我的第一个示例中生成图像 1-6;

printf %s\\n "$ExifListAll" | tr '\t' ' ' | grep \
-E "$DateTimeOrigFirst|$DateTimeOrig1SecMinus|$DateTimeOrig1SecPlus"

再次感谢。

【讨论】:

    猜你喜欢
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    相关资源
    最近更新 更多