1

我目前正在处理一个处理 csv 文件的脚本,并在此过程中更正它们的某些方面。如果需要,它所做的一件事是正确的时间格式。发生两种类型的转换:

 xx:xx:xx to PTxxHxxMxxS
 10:03:45 to PT10H03M45S

我已经能够使用以下方法(见下文)来做到这一点,尽管我试图找出如何使用 sed 或 awk 来加快进程。除了实际的转换过程之外,我还想记录所做的更改(比如转换 4 次值,计数器将增加到 4),我可以使用 if 轻松完成下面的语句(虽然没有显示),虽然我不太了解使用 sed/awk 做这件事。

 istimef=$( echo "$Sfcpp6" | grep ".*:.*:.*" )
                    if [ "$istimef" != "" ]; then
                            hs=$( echo "$Sfcpp6" | cut -d ':' -f 1 )
                            mn=$( echo "$Sfcpp6" | cut -d ':' -f 2 )
                            sc=$( echo "$Sfcpp6" | cut -d ':' -f 3 )
                            Sfcpp6=$( echo "PT"$hs"H"$mn"M"$sc"S" )
                            echo "$Sfcp6"
                    fi

它本质上检查时间值是否存在,然后执行转换。

4

4 回答 4

2

令人惊讶的是,您需要多少进程和子shell 来完成这项任务!我总是对人们的聪明才智和创造力感到惊讶。我计算了 10 个子外壳和 4 个进程生成。

看,您可以在不产生一个进程且无需任何子shell 的情况下实现完全相同的效果。我们在这里谈论加速!

第一个任务,给定一个形式为 的字符串,尽可能高效地xx:yy:zz将其转换为(看,只有一个命令!和一个内置命令!没有!):PTxxHyyMzzSsed

$ string='12:34:56'
$ printf -v transformed 'PT%sH%sM%sS' ${string//:/ }
$ # Done! Don't believe me?
$ echo "$transformed"
PT12H34M56S

现在,在执行此操作之前,您可能需要检查字符串是否为xx:yy:zz. 为此退出grep。只需这样测试它:

if [[ "$string" = *:*:* ]]; then
    echo "ok"
else
    echo "not ok"
fi

因此,您向我们展示的脚本部分会更有效率,因此:

if [[ "$Sfcpp6" = *:*:* ]]; then
    printf -v Sfcp6 'PT%sH%sM%sS' ${Sfcpp6//:/ }
    echo "$Sfcp6"
fi

总计:0 个子外壳,0 个进程产生。

或者,如果您的目标只是回显转换后的字符串:

if [[ "$Sfcpp6" = *:*:* ]]; then
    printf 'PT%sH%sM%sS\n' ${Sfcpp6//:/ }
fi
于 2012-12-01T20:53:25.230 回答
1

sed解决方案:用于\(...\)捕获数字,字符类[0-9]以匹配任何数字。

sed 's/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\)/PT\1H\2M\3S/'
于 2012-12-01T20:12:52.007 回答
0

如果要计算替换的行:

perl -pe '
    END{print "count=$count\n"}
    s/(\d{2}):(\d{2}):(\d{2})/PT$1H$2M$3S/ && $count++
' file.txt
于 2012-12-01T20:52:36.403 回答
0

@choroba 发布的这个 sed 解决方案的 GNU awk 等效项:

sed 's/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\)/PT\1H\2M\3S/'

将非常相似:

awk '{print gensub(/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/,"PT\\1H\\2M\\3S","")}'

但是可以对 awk 解决方案进行简单的修改,以解决您的问题“是否可以让 sed 记录它所做的更改?”:

awk '{orig=$0; $0=gensub(/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/,"PT\\1H\\2M\\3S",""); print} $0 != orig{count++} END{printf "%d changes made.\n",count}'

而 sed 解决方案不能。

于 2012-12-02T14:48:32.637 回答