Search code examples
datesedunix-timestampcommand-substitution

Replace a date string in sed with the ouput of a custom function with arguments


I have a bash script which echos out an html file like this ./foo.sh > out.html In the html there are timestamps in the following format 2019-02-24T17:02:19Z.

I wrote a function to convert the time stamp to the time delta between the timestamp and now.

my_uptime(){
    START=$(date -d "$1" "+%s")
    NOW=$(date "+%s")
    STD=$(echo "($NOW-$START)/3600" | bc)
    MIN=$(echo "(($NOW-$START)/60)%60" | bc)
    echo "Uptime $STD h $MIN min"
}

Now I want to replace the timestamp with the output of my_uptime directly in the stream. I tried this:

echo "<p>some html</p>
2019-02-24T17:02:19Z
<p>some more html</p>" | sed -r "s/[0-9\-]+T[0-9:]+Z/$(my_uptime \0)/"

This fails because the command substitution doesn't recognize the back reference and puts in a literal 0. Is there another way to achieve this? Preferably directly in the stream.


Solution

  • ... | sed -r "s/[0-9\-]+T[0-9:]+Z/$(my_uptime \0)/"
    

    This code is attempting to pass the matched value from sed's s/// into the shell function. However, $(...) is expanded before sed even sees it.

    Using sed is probably not appropriate here.

    Here's a perl replacement that effectively combines your shell function and sed:

    ... | perl -ple '
        if (/([0-9-]+T[0-9:]+Z)/) {
            $s = `date -d "$1" +%s`;
            $n = time;
            $h = int(($n-$s)/3600);
            $m = int(($n-$s)/60)%60;
            $_ = "Uptime $h h $m min";
        }'
    

    You could probably do something similar in awk.