Wednesday, June 13, 2012

Swap every 2 lines in a file



In an earlier article, we had discussed the different ways in which we can join every two lines in a file. In this article, we will see the different ways in which we can swap every two lines in a file.

Let us consider a file with the following contents:
$ cat file
Linux
Solaris
AIX
Ubuntu
Fedora
1. The first sed solution for swapping 2 lines:
$ sed 'N;s/\(.*\)\n\(.*\)/\2\n\1/' file
Solaris
Linux
Ubuntu
AIX
Fedora
  The N command reads the next line into the pattern space. Using the substitution(s) function, we group the individual lines separately and print the second line(\2) first followed by the first line(\1).

2. Another one using sed. This is a little tricky.
$ sed -n '{h;${p;q;};n;G;p;}' file
Solaris
Linux
Ubuntu
AIX
Fedora
      Every time a line is read, it is temporarily stored in the hold space(h). Then, the next line(n) is read into the pattern space. The line in the hold space is concatenated(G) with the pattern space. And the pattern space is printed(p).

    ${p;q} -  This is needed especially to handle files which has an odd number of lines. When the file has odd number of lines, there is no next line to read, simply print the line in the pattern space(p) and quit(q).

3. This awk solution is the best of all.
$ awk '{getline x;print x;}1' file
Solaris
Linux
Ubuntu
AIX
Fedora
     Every iteration in awk works on a particular line in the file sequentially. getline x command of awk reads the next line into the variable x, however the current line is still present in the awk special variable $0. print x prints the next line, while the '1' present outside prints the original line which is $0, and hence we get the lines swapped.

4. Another awk solution.
$ awk 'NR%2{x=$0;next}{print $0"\n"x;}END{if(NR%2)print;}' file
Solaris
Linux
Ubuntu
AIX
Fedora
     NR gives the line number. When the line number of a line is odd, it is stored temporarily in x. When an even numbered line is processed, the even numbered line is processed first followed by the one present in x. The END label is specifically needed to handle a file with odd number of lines since it will remain in x, if left.

5. A pure shell script to swap the lines:
#!/usr/bin/bash

while read line
do
   if [ -z "$x" ]; then
           x=$line
   else
           echo $line
           echo $x
           unset x
   fi
done < file
[ -n "$x" ] && echo $x
 Every line when it is read is stored in the variable x if empty. Else, the current line is printed followed by x and x is unset. The last line is needed to handle a file with odd numbered lines.

Note: Though this is bash script, it should work on bourne and  ksh as well.

No comments:

Post a Comment