sed反向引用和命令插值

时间:2013-10-14 16:44:47

标签: bash sed

我有一个有趣的问题,使用仅使用sed 将短月份字符串(ex“Oct”)替换为相应的数字值(ex“10),给出如下字符串:

Oct 14 09:23:35 some other input

直接通过sed替换为:

14-10-2013 09:23:25 some other input

以下所有内容实际上都与解决月份字符串的小问题无关 - >数字转换;我更感兴趣的是理解我在尝试用sed解决这个问题时遇到的一些奇怪的行为。

没有任何此字符串替换的尝试(echo语句代替我脚本中的实际输入):

    ...
    MMM_DD_HH_mm_SS="([A-Za-z]{3}) ([0-9]{2}) (.+:[0-9]{2})"
    echo "Oct 14 09:23:35 some other input" | sed -r "s/$MMM_DD_HH_mm_ss (.+)/\2-\1-\3 \4/"

然后如何将反向引用\1转换为数字。当然,人们会考虑使用命令插值和反向引用作为参数:

...
TestFunc()
{
    echo "received input $1$1"
}
...
echo "Oct 14 09:23:35 some other input" | sed -r "s/$MMM_DD_HH_mm_ss (.+)/\2-$(TestFunc \\1)-\3 \4/"

其中TestFunc将是date命令的变体(由Jotne在下面提出),echo'd日期时间组作为输入。这里TestFunc只是一个echo,因为我对函数认为是$1的价值的行为更感兴趣。

在这种情况下,带有sed的{​​{1}}会产生输出:

TestFunc

这表明sed实际 在命令替换14-received input OctOct-09:23:35 some other input 中插入反向引用\1,以便$(...)处理(似乎接收TestFunc作为局部变量\1)。

但是,所有使用本地$1做更多事情的尝试都会失败。例如:

$1

返回:

TestFunc()
{
    echo "processed: $1$1" > tmp.txt # Echo 1

    if [ "$1" == "Oct" ]; then
       echo "processed: 10"
    else
       echo "processed: $1$1"        # Echo 2
    fi
}

14-processed: OctOct-09:23:35 some other input 已被替换为Echo 2,但$1包含值tmp.txt;好像没有将反向引用插入到命令替换中。即使更奇怪,processed: \1\1条件也会因if!=“10月”而失败,但它会落到$1语句中,表明echo =“10月”。

我的问题是为什么反向引用插入工作在Echo 2而不是Echo 1?我怀疑反向引用插入根本不起作用(假设$1中的if语句失败),而是发生了一些微妙的事情,这使得替换似乎在以下情况下正常工作回声2;什么是微妙的?

解决方案

进一步思考后,我相信我明白了发生了什么:

  • TestFunc作为文字\\1传递给命令替换子例程/子函数。这就是子函数中的相等测试失败的原因。

  • \1函数 正确处理字符串echo\\1。因此$1将命令替换的结果返回echo "aa$1aa" sed。其他功能(例如aa\1aa)也“看到”rev$1

  • \1然后将sed中的\1插入为aa\1aa或其他任何反向引用,以便将Oct返回给用户。

由于正则表达式中的命令替换显然有效,如果aaOctaa替换sed(或\\1,无论如何)的值,使用后面的 ,那将会非常酷strong>执行命令替换\1;这会显着增加sed的力量......

2 个答案:

答案 0 :(得分:1)

使用正确的工具:

date -d "Oct 14 09:23:35" +"%d-%m-%Y %H:%M:%S"
14-10-2013 09:23:35

日期会读取您的输入并将其转换为您喜欢的任何格式

答案 1 :(得分:0)

这可能适合你(GNU sed):

s/$/\nJan01...Oct10Nov11Dec12/;s/(...) (..) (..:..:.. .*)\n.*\1(..).*/\2-\4-2013 \3/;s/\n.*//' file

在行尾添加查找并使用后引用进行匹配,确保在所有情况下都删除查找表。

以下是将反向引用传递给函数的示例:

f(){ echo "x$1y$1z"; }
echo a b c | sed -r  's/(.) (.) (.)/'"$(f \\2)"'/'

返回:

xbybz

HTH