Monday, January 31, 2022

[SOLVED] Reverse input order with sed

Issue

I have a file, lets call it 'a.txt' and this file contains the following text line

do to what

I'm wondering what the SED command is to reverse the order of this text to make it look like

what to do

Do I have to do some sort of append? Like append 'do' to 'to' so it would look like

to ++ do (used ++ just to make it clear)


Solution

answer

As this question was tagged , my 1st answer was:

First (using arbitraty _ to mark viewed spaces, when a.txt contain do to what:

sed -e '
    :a;
    s/\([^_]*\) \([^ ]*\)/\2_\1/;
    ta;
    y/_/ /;
   ' a.txt
what to do

than, when a.txt contain do to to what:

sed -e '
    :a;
    s/^\(\|.* \)\([^+ ]\+\) \2\([+]*\)\(\| .*\)$/\1\2\3+\4/g;
    ta;
    :b;
    s/\([^_]*\) \([^ ]*\)/\2_\1/;
    tb;
    y/_/ /;
   ' <<<'do to to to what'
what to++ do

There is one + for each supressed duplicated word:

sed -e ':a;s/^\(\|.* \)\([^+ ]\+\) \2\([+]*\)\(\| .*\)$/\1\2\3+\4/g;ta;
        :b;s/\([^_]*\) \([^ ]*\)/\2_\1/;tb;
        y/_/ /;' <<<'do do to what what what what'
what+++ to do+

answer

But as there is a lot of people searching for simple solutions, there is a simple way:

xargs < <(uniq <(tac <(tr \  \\n <<<'do do to what what what what')))
what to do

this could be written:

tr \  \\n <<<'do do to what what what what' | tac | uniq | xargs 
what to do

or even with some scripting:

revcnt () { 
    local wrd cnt plut out="";
    while read cnt wrd; do
        printf -v plus %$((cnt-1))s;
        out+=$wrd${plus// /+}\ ;
    done < <(uniq -c <(tac <(tr \  \\n )));
    echo $out
}

Will do:

revcnt <<<'do do to what what what what' 
what+++ to do+

Or as pure

revcnt() { 
    local out i;
    for ((i=$#; i>0; i--))
    do
        [[ $out =~ ${!i}[+]*$ ]] && out+=+ || out+=\ ${!i};
    done;
    echo $out
}

where submited string have to be submitted as argument:

revcnt do do to what what what what
what+++ to do+

Or if prossessing standard input (or from file) is required:

revcnt() { 
    local out i arr;
    while read -a arr; do
        out=""
        for ((i=${#arr[@]}; i--; 1))
        do
            [[ $out =~ ${arr[i]}[+]*$ ]] && out+=+ || out+=\ ${arr[i]};
        done;
        echo $out;
    done
}

So you can process multiple lines:

revcnt <<eof
do to what
do to to to what
do do to what what what what
eof
what to do
what to++ do
what+++ to do+


Answered By - F. Hauri
Answer Checked By - Timothy Miller (WPSolving Admin)