【发布时间】:2013-10-22 07:17:35
【问题描述】:
我遇到了一个有趣的问题,使用 only sed 将短月份字符串(例如“Oct”)替换为相应的数字值(例如“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 和 TestFunc 会产生输出:
14-received input OctOct-09:23:35 some other input
这表明 sed 实际上正在将反向引用 \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
$1 已被替换为 Echo 2,但 tmp.txt 包含值 processed: \1\1;就好像反向引用没有被插入到命令替换中一样。更奇怪的是,if 条件因$1 != "Oct" 而失败,但它落入echo 语句,表明$1 = "Oct"。
我的问题是为什么反向引用插入在 Echo 2 的情况下有效但在 Echo 1 的情况下无效?我怀疑反向引用插入根本不起作用(鉴于TestFunc 中的if 语句失败),而是发生了一些微妙的事情,这使得替换在Echo 2 的情况下似乎正常工作;那是什么微妙之处?
解决方案
经过进一步思考,我相信我明白发生了什么:
\\1作为文字\1传递给命令替换子例程/子函数。这就是子函数中的相等性测试失败的原因。但是
echo函数 正确地将字符串\\1处理为$1。所以echo "aa$1aa"将命令替换的结果返回到sed作为aa\1aa。rev等其他函数也“看到”$1为\1。sed然后在aa\1aa中插入\1作为Oct或任何反向引用,以将aaOctaa返回给用户。
由于正则表达式中的命令替换显然有效,如果sed 将\\1(或\1,等等)的值替换为反向引用在执行命令替换之前,那将是非常酷的$(...);这将显着增加 sed 的能力......
【问题讨论】: