我遇到了一个有趣的问题,仅使用 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/"
将'd 日期时间组作为输入TestFunc
的命令变体date
(如下 Jotne 建议的)在哪里。echo
这里 TestFunc 只是一个,echo
因为我对函数认为的值的行为更感兴趣$1
。
在这种情况下,sed
withTestFunc
产生输出:
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
条件以 != "Oct" 失败$1
,但它落入指示= "Oct"的echo
语句。$1
我的问题是为什么反向引用插入在 Echo 2 而不是 Echo 1 的情况下有效?我怀疑反向引用插入根本不起作用(鉴于if
in 中的语句失败TestFunc
),而是发生了一些微妙的事情,使得替换在 Echo 2 的情况下似乎正常工作;那是什么微妙之处?
解决方案
经过进一步思考,我相信我了解发生了什么:
\\1
作为文字传递给命令替换子例程/子函数\1
。这就是子函数中的相等测试失败的原因。但是该
echo
函数正确地将字符串处理\\1
为$1
. 所以echo "aa$1aa"
将命令替换的结果返回到sed
asaa\1aa
。其他功能,例如rev
“see”$1
as\1
。sed
然后插入\1
作为或任何反向引用aa\1aa
,Oct
以返回aaOctaa
给用户。
由于正则表达式中的命令替换显然有效,如果在执行命令替换之前用反向引用替换(或,其他)sed
的值会非常酷;这将显着增加 sed 的力量......\\1
\1
$(...)