gpt4 book ai didi

linux - 用基于匹配组的评估字符串替换字符串(优雅的方式,不使用 for .. in)

转载 作者:太空狗 更新时间:2023-10-29 11:38:41 26 4
gpt4 key购买 nike

我正在寻找一种方法来替换由正则表达式匹配的文件字符串,以及另一个将从匹配字符串中生成/评估的字符串。

比如我要替换这个文件中的时间戳(timestamp + duration)

1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
...

通过人类可读的日期表示(日期范围)。

直到现在,我总是使用像 Bash 这样的 shell 脚本来遍历每一行,匹配行 X,获取匹配的组字符串并在处理后打印行,例如这样(从内存中):

IFS="
"
for L in `cat file.txt`; do
if [[ "${L}" =~ ^([0-9]{1,10})\ ([0-9]{1,4})\ .*$ ]]; then
# Written as three lines for better readability/recognition
echo -n "`date --date=@${BASH_REMATCH[1]}` - "
echo -n "`date --date=@$(( ${BASH_REMATCH[1]} + ${BASH_REMATCH[2]} ))`"
echo ""
else
echo "$L"
fi
done

我想知道是否有这样的虚构(?)“sed-2.0”:

cat file.txt | sed-2.0 's+/^\([0-9]\{1,10\}\) \([0-9]\{1,4\}\) .*$+`date --date="@\1"` - `date --date="@$(( \1 + \2 ))`'

而 sed-2.0 替换中的反引号将被评估为传递匹配组 \1\2 的 shell 命令。

我知道这不能按预期工作,但我想写这样的东西。

编辑1

编辑上述问题:在 Bash 脚本示例的 if 中添加了缺少的 echo ""

这应该是预期的输出:

Do 3. Jan 15:15:00 CET 2013 - Do 3. Jan 16:15:00 CET 2013
Maybe intermediate strings...
Do 3. Jan 16:15:00 CET 2013 - Do 3. Jan 17:15:00 CET 2013
Maybe intermediate strings...
...

请注意,时间戳取决于时区。

编辑2

编辑上述问题:修复了 Bash 脚本示例的语法错误,添加了注释。

编辑3

编辑上述问题:修复了 Bash 脚本示例的语法错误。将短语“老式示例”更改为“Bash 脚本示例”。


摘要Kent的和glenn jackman的回答

这两种方法存在巨大差异:执行时间。我比较了所有四种方法,结果如下:

gawk 使用 strftime()

/usr/bin/time gawk '/^[0-9]+ [0-9]+ / {t1=$1; $1=strftime("%c -",t1); $2=strftime("%c",t1+$2)} 1' /tmp/test
...
0.06user 0.12system 0:00.30elapsed 60%CPU (0avgtext+0avgdata 1148maxresident)k
0inputs+0outputs (0major+327minor)pagefaults 0swaps

gawk 通过 getline ( Gnu AWK Manual ) 使用执行

/usr/bin/time gawk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=@"$1|getline d1; "date --date=@"l|getline d2;print d1" - "d2;next;}1' /tmp/test
...
1.89user 7.59system 0:10.34elapsed 91%CPU (0avgtext+0avgdata 5376maxresident)k
0inputs+0outputs (0major+557419minor)pagefaults 0swaps

自定义 Bash 脚本

./sed-2.0.sh /tmp/test
...
3.98user 10.33system 0:15.41elapsed 92%CPU (0avgtext+0avgdata 1536maxresident)k
0inputs+0outputs (0major+759829minor)pagefaults 0swaps

sed 使用 e 选项

/usr/bin/time sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=@\1 )" - "$(date --date=@$((\1+\2)))#ge' /tmp/test
...
3.88user 16.76system 0:21.89elapsed 94%CPU (0avgtext+0avgdata 1272maxresident)k
0inputs+0outputs (0major+1253409minor)pagefaults 0swaps

输入数据

for N in `seq 1 1000`; do echo -e "$(( 1357226100 + ( $N * 3600 ) )) 3600 ...\nSomething else ..." >> /tmp/test ; done

我们可以看到使用strffime() 方法的AWK 是最快的。但即使是 Bash 脚本也比使用 shell 执行的 sed 更快。​​

Kent 向我们展示了一种更通用、更通用的方法来完成我所要求的。我的问题实际上不仅限于我的时间戳示例。在这种情况下,我必须完全这样做(用人类可读的日期表示替换时间戳 + 持续时间),但我遇到了必须执行其他代码的情况。

glenn jackman向我们展示了一个具体的解决方案,适用于可以直接在AWK中进行字符串操作和计算的情况。

因此,这取决于您拥有的时间(或您的脚本可能运行的时间)、数据量和用例应该首选哪种方法。

最佳答案

基于您的示例输入:

gawk '/^[0-9]+ [0-9]+ / {t1=$1; $1=strftime("%c -",t1); $2=strftime("%c",t1+$2)} 1'

输出

Thu 03 Jan 2013 09:15:00 AM EST - Thu 03 Jan 2013 10:15:00 AM EST ...
Maybe intermediate strings...
Thu 03 Jan 2013 10:15:00 AM EST - Thu 03 Jan 2013 11:15:00 AM EST ...
Maybe intermediate strings...
...

关于linux - 用基于匹配组的评估字符串替换字符串(优雅的方式,不使用 for .. in),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14102504/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com