【问题标题】:comparing dates using awk in bash在 bash 中使用 awk 比较日期
【发布时间】:2017-02-18 06:13:48
【问题描述】:

所以我有一个文件,每一行都有一些信息和日期(生日)。我想在给定日期之后打印带有日期的行。我使用这个 awk 命令

awk -F '|' 'FNR>1 $dateA<=$5 {print $1" "$2" "$3" "$4" "$5" "$6" "$7" "$8}' $FILE

但它不能正常工作(打印所有文件行)。日期采用 YYYY-MM-DD 格式,因此字母顺序也是按时间顺序排列的。

编辑:输入文件中的一些行

1099511628908|Chen|Wei|female|1985-08-02|2010-05-24T20:52:26.582+0000|27.98.244.108|Firefox
1099511633435|Smith|Jack|male|1981-04-19|2010-05-26T03:45:11.772+0000|50.72.193.218|Internet Explorer
1099511635042|Kiss|Gyorgy|male|1984-09-14|2010-05-16T22:57:41.808+0000|91.137.244.86|Chrome
1099511635218|Law-Yone|Eric|male|1987-01-20|2010-05-26T20:10:22.515+0000|203.81.95.235|Chrome
1099511638444|Jasani|Chris|female|1981-05-22|2010-04-29T20:50:40.375+0000|196.223.11.62|Firefox
2199023256615|Arbelaez|Gustavo|male|1986-11-02|2010-07-17T18:53:47.633+0000|190.96.218.101|Chrome

【问题讨论】:

  • 您输入的命令是否准确?您在此示例中使用单引号,因此请注意您的 $dateA 变量可能不会被扩展。
  • 扩展了吗?你什么意思?
  • 我的意思是在这个例子中$dateA不会被shell替换为2016-10-09,而是作为字符串$dateA提供给awk。由于 awk 不知道这个变量,它可能会用空字符串替换它。
  • dateA 是在我正在编写的代码中较早初始化的变量。 awk 如何将 dateA 视为空字符串?
  • 如果它是一个shell变量,将它嵌入单引号之间会阻止它被它的值替换。我的意思是,试试echo $HOMEecho '$HOME'。使用单引号,您将字符串 $dateA 提供给 awk 而不是此变量的值。

标签: bash shell date awk


【解决方案1】:

正如其他人所说,单引号中的变量不会被shell扩展。 awk 将看到变量的名称,而不是它的值。

一种可能的解决方案是这样做(假设比较字符串是正确的):

dateA='1985-01-01'
infile='file to read values from'
awk -F '|' -v dateA="$dateA" '{if (FNR>1 && dateA<=$5) {print}}' "$infile"

一个更惯用的解决方案(有点不太清楚):

awk 'FNR>1 && dateA<=$5' FS='|' dateA="$dateA" "$infile"

或者(是的,所有的引用都需要):

awk 'FNR>1 && "'"$dateA"'"<=$5' FS='|' "$infile"

但在考虑使用此选项之前read this about code injection

【讨论】:

  • 好吧,在你之前有人写过类似的东西,除了这个有效而那个无效。不知道是什么原因,非常感谢! :)
  • Awk 不是 C。你写的 {if (FNR&gt;1 &amp;&amp; dateA&lt;=$5) {print}} 是 C 风格的语法,它会用 awk 写成 FNR&gt;1 &amp;&amp; dateA&lt;=$5
  • 感谢@EdMorton,我认为这个用户需要更清晰的意图描述,但是是的,你是绝对正确的。
  • @EdMorton 再看一遍,连打印也是可选的:awk 'FNR&gt;1 &amp;&amp; dateA&lt;=$5' FS='|' dateA="$dateA" "$infile"
  • 对,这就是我忽略它的原因。另外,不要做"'"$dateA"'"。谷歌一下。
【解决方案2】:

为此工作:

awk -vdateA=1985-01-01 -F '|' 'FNR>1 dateA<=$5' $FILE
    ~~~~~~~~~~~~~~~~~~

【讨论】:

  • 这是 gawk 特有的,因为 -v 之后缺少空格。
【解决方案3】:

您的变量 $dateA 是一个 shell 变量。如果你将它嵌入单引号之间,它不会被 shell 解释(它不会被它的值替换)并且会“按原样”转发给 awk。

Awk 接收字符串$dateA。它认为它是一个 awk 变量,但它没有任何值,因此它使用空字符串代替。您的所有日期都被认为比空字符串“更大”,因此所有行都匹配并被打印。

对此有几种解决方案。在 Gilles Quenot 的旁边,您手动向 awk 指示 dateA 是一个 shell 变量,您也可以像这样“从引号中”取出它:

awk -F '|' 'FNR>1 '$dateA'<=$5 {print $1" "$2" "$3" "$4" "$5" "$6" "$7" "$8}' $FILE
                  ^      ^

这适用于日期为整数值的情况,但不适用于 YYYY-MM-DD 格式。在后一种情况下,我们需要……用引号转义变量以告诉 awk 这是一个字符串。

我们想做一些看起来像"$dateA" 的东西。由于我们已经添加了单引号不是将$dateA 原样传递给 awk,因此我们必须在其周围添加双引号:"'$dateA'"。这样,shell 首先将dateA 替换为其值,然后删除单引号,并将"1985-08-23" 提供给awk。

所以这条线是:

awk -F '|' 'FNR>1 && "'$dateA'"<=$5 {print $1" "$2" "$3" "$4" "$5" "$6" "$7" "$8}' $FILE

编辑:不确定这是否取决于 awk 版本,但我在此示例中遇到语法错误,并且还必须将 FNR&gt;1 '$date'&lt;$5 替换为 FNR&gt;1 &amp;&amp; '$date'&lt;$5(附加 &amp;&amp;)。 GNU awk 在这里。

【讨论】:

  • 如果我双引号仍然没有变化
  • 加上&amp;&amp;,这条线对我有用。我将dateA 设置为1985,它只打印两个结果。所以我真的不知道:-/ 你检查你的dateA 变量是否包含你想要的值?
  • 我在发布之前检查过,是的 dateA 确实将我给它的值作为参数。如果您输入像 1985-08-23 这样的完整日期,它仍然有效吗?编辑我检查了 1985 年,是的,它可以工作,但它不适用于完整日期:/
  • 不要这样做。永远不要让 shell 变量扩展成为 awk 脚本文本的一部分,它容易出错并导致各种神秘错误。只需从 shell 变量的值中设置一个 awk 变量,然后在脚本中使用 awk 变量。
猜你喜欢
  • 2015-01-01
  • 2022-10-23
  • 2013-01-26
  • 1970-01-01
  • 2011-02-19
  • 2017-08-26
  • 2021-05-01
  • 2015-07-25
  • 1970-01-01
相关资源
最近更新 更多