How to swap the first line with last line in a text file using SED/AWK


I am trying to swap the first line with last line in a text file in unix file has:

line1 line2 line3 line4 line5 line6

I want like this:

line6 line2 line3 line4 line5 line1

I am using sed -n -e '1 s/^.*$/$p' file . Which is not happening.


<em>EDIT2:</em> As per Ed sir's comment adding this solution too here which will be more suitable in case 2nd line is empty then also it will work.

awk 'NR==1{first=$0;next} NR>2{val=val prev ORS} {prev=$0} END{print prev ORS val first} Input_file <hr />

<em>EDIT:</em> To exchange only first and last line following may help you(considering that your Input_file is same as shown sample).

awk 'FNR==1{first=$0;next} {val=(val?val ORS prev:prev?$0:"")} {prev=$0} END{print $0 ORS val ORS first}' Input_file


awk ' FNR==1{ ##Checking if line is first line then do following. first=$0; ##Creating varable first whose value is current line value. next ##next will skip all further statements from here. } { val=(val?val ORS prev:prev?$0:"") ##Creating variable named val here whoe value is concatenating to its own value with variable prev value. } { prev=$0 ##Creating variable prev whose value will be current value of line but will become previous value for next line. } END{ print $0 ORS val ORS first ##Printing current line ORS val ORS and first here. }' Input_file ##Mentioning Input_file name here.

Could you please try following and let me know if this helps you.

awk -v from=1 -v to=6 'FNR==from{source=$0;next} FNR==to{target=$0;next} {val=val?val ORS $0:$0} END{print target ORS val ORS source}' Input_file

This might work for you (GNU sed):

sed 'H;$!d;x;s/\n\([^\n]*\)\(\n.*\n\)\(.*\)/\3\2\1/' file

Copy the whole file into the hold space (HS) and after the last line, swap to the HS, split the file into first line, middle and last line and substitute the first and last lines.

A two pass alternative solution:

sed -n '1s/.*/$c&/p;$s/.*/1c&/p' file | sed -f - file

Create a sed script to change the first line to the last and last line to the first.

Another solution using cat, head, tail and sed:

cat <(tail -1 file) <(sed '1d;$d' file) <(head -1 file)

Another sed solution:

sed -E '1h;1d;:a;N;$!ba;s/(.*)\n(.*)/\2\n\1/;G' file

In sed, you'll need to make two passes; it probably makes more sense to use ed instead. Then we just need two move commands - move the last line to just after line 1, then move the first line to the end:

<pre class="lang-none prettyprint-override">$m1 1m$ <h2>Demo</h2> #!/bin/bash set -euo pipefail # Create our input file file=$(mktemp) trap 'rm "$file"' EXIT cat >"$file" <<END line1 line2 line3 line4 line5 line6 END echo Before: cat "$file" echo # Make the change ed -s "$file" <<<$'$m1\n1m$\nwq' # Show the result echo After: cat "$file"

If you need to write a different output file, you can of course add a filename argument to the wq command, as usual.


Just in case a oneliner mixing, head, tail and sed:

$ FIRST=$(head -1 file.txt) LAST=$(tail -1 file.txt) \ sed "1 s/^.*$/${LAST}/" file.txt | sed "$ s/^.*$/${FIRST}/"

For very large files, you might be interested in a double pass:

awk '(NR!=FNR){print (FNR==1 ? t : (FNR==c ? h : $0) ); next } (NR==1){h=$0}{t=$0;c=NR}' file file

Using the sponge util:

f=file { tail -1 $f ; tail -n +2 $f | head -n -1 ; head -1 $f ; } | sponge $f