Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Awk reverse both lines and words

Tags:

reverse

awk

I'm new to programming language and stuff so I have to reverse with awk all the lines and as well all the words in those lines, from a file and print them out.

"File1" to reverse:

aa bb cc

foo do as

And the output printing of the "File1" should be this:

as do foo

cc bb aa

I tried this for word reverse in each line:

for (i=NF; i>1; i--) printf("%s ",$i); printf("%s\n",$1)

but if I want to print the reversed lines I have to do this

{a[NR]=$0
}END{for(i=NR; i; i--) print a[i]}

I need to work with two files with this command in terminal:

awk -f commandFile FileToBePrinted

The problem is I'm beginer in all this and I don't know how to combine those two. Thanks!

like image 486
Mircea Voivod Avatar asked Mar 27 '12 14:03

Mircea Voivod


3 Answers

Kev's solution looks to reverse the text in each word. You example output doesn't show that, but his key point is to use a function.

You have the code you need, you just need to rearrange it a little.

cat file1
aa bb cc
foo do as

cat commandFile

function reverse( line ) {
  n=split(line, tmpLine)
  for (j=n; j>0; j--) {
    printf("%s ",tmpLine[j] )
  }

}
# main loop
{ a[NR]=$0 }

# print reversed array
END{ for(i=NR; i>0; i--) printf( "%s\n",  reverse(a[i]) ) }

Running

 awk -f commandFile file1

output

as do foo
cc bb aa

There were a couple of minor changes I made, using n=split(line, tmpLine) ... print tmpLine[j], is a common method of parsing a line of input in a function to print it out. I don't think the $1 vars have scope from a value passed in from an array (your a[i] value), so I changed it to split..tmpLine[j]. I also found that the 'i' variable from END section was kept in scope in the function reverse, so I changed that to j to disambiguate the situation.


I had to figure out a few things, so below is the debug version that I used.

If you're going to have access to gawk, then you'll do well to learn how to use the debugger that is available. If you're using awk/gawk/nawk on systems without a debugger, then this is one method for understanding what is happening in your code. If you're redirecting your programs output to a file or pipe, AND if you system supports "/dev/stderr" notation, you could print the debug lines there, i.e.

 #dbg print "#dbg0:line=" line > "/dev/stderr"

Some systems have other notations for accessing stderr, so if you'll be doing this much, it is worthwhile to find out what is available.

cat commandFile.debug
function reverse( line ) {
  n=split(line, tmpLine)
  #dbg print "#dbg0:line=" line
  #dbg print "#dbg1:n=" n "\tj=" j "\ttmpLine[j]=" tmpLine[j]
  for (j=n; j>0; j--) {
    #dbg print "#dbg2:n=" n "\tj=" j "\ttempLine[j]=" tmpLine[j]
    printf("%s ",tmpLine[j] )
  }

}
# main loop
{ a[NR]=$0 }

# print reversed array
#dbg END{ print "AT END";  for(i=NR; i>0; i--) printf( "#dbg4:i=%d\t%s\n%s\n", i, a[i] , reverse(a[i])
 ) }
END{ for(i=NR; i>0; i--) printf( "%s\n",  reverse(a[i]) ) }

I hope this helps.

like image 100
shellter Avatar answered Sep 22 '22 02:09

shellter


awk '
{
    x=reverse($0) (x?"\n":"") x
}

END{
    print x
}

function reverse(s,    p)
{
    for(i=length(s);i>0;i--)
        p=p substr(s,i,1)
    return p
}' File1
like image 42
kev Avatar answered Sep 22 '22 02:09

kev


use tac to reverse the lines of the file, then awk to reverse the words.

tac filename | awk '{for (i=NF; i>1; i--) printf("%s ",$i); printf("%s\n",$1)}'

You could also use something like Perl that has list-reversing functions built-in:

tac filename | perl -lane 'print join(" ", reverse(@F))'
like image 39
glenn jackman Avatar answered Sep 20 '22 02:09

glenn jackman