在 Unix 中使用时间戳将单行分成多行

在 Unix 中使用时间戳将单行分成多行

给定一个没有固定字段分隔符模式的输入行,如下所示。

x="15:23:46 Let's do this 15:23:47 It's easy: to do   for    you 15:23:48 You will ## have solution soon   0"

我试图根据时间戳模式将其分成单独的行,因此预期输出如下。

15:23:46 Let's do this
15:23:47 It's easy: to do for you
15:23:48 You will have solution soon
0

请注意,行尾有 0,也应该打印在换行符上。我需要将其用作其余代码的返回状态。

当时间戳不同时,我能够获得结果,但是当其中一些时间戳相同时,就会导致意外的输出。

x=”15:23:46我们开工吧15:23:46这很简单:为您做 15:23:48 您很快就会 ## 找到解决方案 0"

观察现在我们有两个相同的时间戳。这就是我被困住的地方。预期输出应该是:

15:23:46 Let's do this
15:23:46 It's easy: to do for you
15:23:48 You will have solution soon
0

我使用的逻辑是获取数组中的所有时间戳,然后迭代时间戳的数量并 grep 查找所需的数据。当具有唯一时间戳时,对我有用的逻辑如下。

#!/bin/sh

timestamp=()
x="15:23:46 Let's do this 15:23:47 It's easy: to do for you 15:23:48 You will have solution soon 0"

timestamp+=(`echo $x | grep -oP '(?>[0-9]{2}:[0-9]{2}:[0-9]{2})'`)
total_timestamps=`echo $x | grep -oP '(?>[0-9]{2}:[0-9]{2}:[0-9]{2})' | wc -l`
status=-1

for i in `seq $total_timestamps`
do
  if [ "$i" -ne "$total_timestamps" ]; then
    echo $x | grep -oP "(?=${timestamp[i-1]}).*(?=${timestamp[i]})"
  fi

  if [ "$i" -eq "$total_timestamps" ]; then
    echo $x | grep -oP "(?=${timestamp[i-1]}).*(?=${timestamp[i]})" | awk '{$NF=""}1'
    status=`echo $x | grep -oP "(?=${timestamp[i-1]}).*(?=${timestamp[i]})" | awk '{print $NF}'`
  fi
done

echo $status

当时间戳在单行中的某些或许多地方相同时,有人可以帮助我,或者将我重定向到已解决类似问题的地方吗?

答案1

使用用于多字符 RS 和 RT 的 GNU awk:

$ awk -v RS='([0-9]{2}(:[0-9]{2}){2})|(0\n$)' 'NR>1{print pRT $0} {pRT=RT} END{printf "%s", RT}' <<<"$x"
15:23:46 Let's do this
15:23:47 It's easy: to do   for    you
15:23:48 You will ## have solution soon
0

或者如果您的 shell 没有<<<运算符:

$ echo "$x" | awk -v RS='([0-9]{2}(:[0-9]{2}){2})|(0\n$)' 'NR>1{print pRT $0} {pRT=RT} END{printf "%s", RT}'
15:23:46 Let's do this
15:23:47 It's easy: to do   for    you
15:23:48 You will ## have solution soon
0

如果您想从输出行中去除尾随空白,只需更改print pRT $0print pRT gensub(/\s+$/,"",1,$0).

答案2

使用GNU sed启用了扩展正则表达式模式的流编辑器实用程序-E

我们在(日期字符串或末尾的一个零)左侧查找一串空格,并将其更改为换行符。然后使用标准习惯用法P;D打印换行符左侧的所有内容,然后将其截断。冲洗并重复,直到整个图案空间被耗尽。

printf '%s\n' "$x" |
sed -Ee '
  s/\s+(([0-9]{2}(:[0-9]{2}){2})|0$)/\n\1/
  P;D
' - | cat -A

15:23:46 Let's do this$
15:23:47 It's easy: to do   for    you$
15:23:48 You will ## have solution soon$
0$

相关内容