【问题标题】:How to change date format in sed?如何更改sed中的日期格式?
【发布时间】:2016-03-08 08:50:08
【问题描述】:

假设我想通过date 命令将时间戳中的日期转换为另一种格式。在控制台中我会说date -d@<timestamp>,但我碰巧想对文本文件中的许多字段执行此操作。

使用esed 中执行(实际上是sed (GNU sed) 4.2.2)我是说:

$ echo 1449158360 | sed -r 's#.*([0-9]{10}).*#date -d@\1 "+%Y";#e'
2015

很好用!

现在我创建了一个虚拟文件myfile

my timestamp is 1449158360 but also I wonder what date was 1359199960.

我想替换为相同但具有时间戳的相对年份:

my timestamp is 2015 but also I wonder what date was 2013.

但是,如果我尝试运行与上面相同的命令,它会失败:

$ sed -r 's#([0-9]{10})#date -d@"\1" "+%Y";#e' myfile
sh: my: command not found
sh: but: command not found

因为sed 将第一个单词解释为要执行的内容。

如果我只获取这些数据而不是其他任何东西,显然它会起作用:

$ sed -r 's#.*([0-9]{10}).*#date -d@"\1" "+%Y";#ge' myfile
2015

所以我想知道:我应该怎么做才能针对sed 中的捕获组调用date 并用它替换文本,考虑到它被其他必须保持不变的文本包围?

【问题讨论】:

  • 不是真的,@TobySpeight 因为我在这里问为什么它没有按照我尝试的方式工作。
  • 您阅读那里的答案了吗?具体来说,my comments on sed s///e - 我推荐 Perl 而不是 sed 来完成这项工作。
  • @TobySpeight 我读过它们,那里甚至有一个已删除的答案:) 我明白这里的重点是关于您在回答中提到的内容,请注意 /e 会导致命令替换替换整个模式空间,因此您可能需要使用保持空间来保留替换前后的文本。这是留给读者的练习 这是我无法执行的最后一部分。稍后我将进行编辑以专注于这个特定问题。

标签: regex bash date sed


【解决方案1】:

正如你所说,使用 e 标志 sed 正在将所有句子作为要执行的东西。

转机可能是这样的。

myfile 更改为:

echo "my timestamp is 1449158360 but also I wonder what date was 1359199960."

然后:

sed -r 's#([0-9]{10})#\`date -d@\1 "+%Y"\`#ge' myfile

希望对你有帮助

【讨论】:

    【解决方案2】:

    e switch in sed 替换将sh -c 应用于不匹配的文本以及从该命令中显而易见:

    echo 'a 1449158360' | sed -r 's#([0-9]{10})#date -d@\1 "+%Y";#e'
    sh: a: command not found 
    

    所以即使我们只匹配1449158360,但sh -c 正在a 1449158360 上运行。

    由于sed 中没有非贪婪和前瞻正则表达式,此解决方法正则表达式可能看起来很疯狂,但这是您可以针对来自文件的多个匹配输入运行它的方式,如您的问题:

    sed -r 's#(([^0-9][0-9]{0,9})*)(\b[0-9]{10}\b)(([0-9]{0,9}[^0-9])*)#printf "%s%s%s" "\1" $(date -d@\3 "+%Y") "\4";#ge' file
    

    基本上我们在这个正则表达式中匹配<before>10-digits<after>

    输出:

    my timestamp is 2015 but also I wonder what date was 2013.
    

    为了澄清所使用的正则表达式,我创建了this demo

    这绝不是e 模式问题的通用解决方案,请将其视为基于正则表达式的解决方法。

    【讨论】:

    • 哇,太漂亮了,非常感谢!我学到了两件事:第一,如何有效地执行sed中的命令。然后,如何使用嵌套的捕获组(我最初想知道\2 在哪里,然后我看到\1 可以是\2 的多个案例)。非常感谢!
    • 是的,不幸的是,由于 sed 正则表达式的限制,即没有惰性量词,没有前瞻和非捕获组,这个正则表达式变得有点复杂。很高兴你喜欢它。这对我来说是一个非常有趣的问题。
    • 谢谢,多亏了这一点,我设法创建了一个方便的命令来输出~/zsh_history,人类可读的日期为sed -E 's/(([^0-9][0-9]{0,9})*)(\b[0-9]{10}\b)(([0-9]{0,9}[^0-9])*)/printf "%s%s%s" "\1" "$(date -ud @\3)" "\4"/ge' ~/.zsh_history | less
    猜你喜欢
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    • 2018-10-12
    • 2020-12-17
    相关资源
    最近更新 更多