Perlu memindahkan baris terakhir file ke baris kedua dari file yang sama

8

Saya memiliki file 'test' di linux dengan data di bawah ini.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Saya perlu memotong baris terakhir file ini dan meletakkannya di posisi kedua. Itu harus terlihat seperti di bawah ini.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Vivek William
sumber

Jawaban:

9

Masalah ini mungkin sebenarnya paling mudah dilakukan ed, karena itu pada dasarnya adalah editor teks yang dapat skrip, daripada prosesor aliran. Menggunakan ed, Anda tidak harus menyimpan semua baris file ke dalam array, misalnya, karena sudah melakukan itu untuk Anda.

# Create test file
~> printf "%s\n" aaaaaa bbbbbb cccccc dddddd eeeeee >test.txt
~> cat test.txt
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

# Use ed to open the file, move the last line after the first, save, and quit
~> printf "%s\n" '$m1' wq | ed test.txt
35
35
~> cat test.txt
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
godlygeek
sumber
5

Tahan metode penyangga:

sed '$x;1!H;1p;$!d;x;s/\n//
' <<\IN
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... yang akan Hmenua setiap baris yang !bukan yang pertama, dan yang pertama pruntuh. Pada $baris terakhir, ia xmengubah ruang pegang dan pola sebelum melakukan yang Hlama - yang membuat baris yang disimpan ditambahkan ke baris terakhir - lalu dmenghapus dari output semua baris yang !bukan yang $terakhir.

Pada $baris terakhir, ia xmengubah spasi lagi, s///mengganti \nkarakter ewline pertama - yang mengatur tambahan yang ditambahkan pada baris 2 - lalu mencetak ulang otomatis lot.

KELUARAN:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

tanpa menggunakan buffer Tahan:

cat <<\IN >infile
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... hanya untuk menyimpan contoh Anda ke file yang sebenarnya ...

sed '1p;$!d;r infile' <infile | sed '3d;$d'

Bahwa pengalihan <infiledengan yang pertama sed's stdin, yang hanya prints baris pertama sebelum deleting dari output semua baris yang !tidak $terakhir. Baris terakhir adalah autoprinted, tetapi juga satu-satunya jalur yang perintah akhir dijalankan - yang adalah untuk rEAD keluar seluruh yang infile lagi ke stdout. Semua itu akan dilewati |pipa ke yang kedua sedyang kemudian hanya harus dmenghapus dari outputnya jalur input ketiga dan terakhir untuk menyelesaikan mengatur ulang.

KELUARAN:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
sumber
keren, +1. Saya tidak ingat Anda pernah memposting awksolusi, apakah Anda sedpenggemar berat atau mungkin Anda menulis sed? ;-)
iruvar
@ 1_CR - saya tidak tahu cara menggunakan awk- saya belum pernah mencoba. mungkin suatu hari nanti ...
mikeserv
2

Pendekatan naif menggunakan awk:

~$ awk '{a[NR]=$0}END{print a[1];print a[NR];for(i=2;i<NR;i++){print a[i]}}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Anda menyimpan setiap baris dalam aarray, lalu mencetak array dalam urutan yang Anda inginkan (baris 1, baris terakhir ( NR) dan dari 2 hingga kedua dari belakang.

Menggunakan kombinasi kepala / ekor dan sed:

~$ head -1 f;tail -1 f;sed '1d;$d' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Cetak baris pertama, terakhir, dan dengan sed hapus 1 dan terakhir.


Dengan sed saja, saya hanya dapat menemukan perintah ini. Saya yakin ada cara yang lebih baik:

~$ sed '${p;x;s/^\n//;p};2,${H;d}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Jika ini adalah baris pertama, cetaklah (default).
Dari baris kedua, letakkan di buffer terus ( H), dan hapus dari ruang pola ( d). Dan jika itu adalah baris terakhir, cetaklah ( p), lalu dapatkan buffer penahan ( x), hapus baris kosong ( s/^\n//) dan cetaklah ( p).

fredtantini
sumber
Insting pertama saya adalah menggunakan metode kepala / ekor. Alternatif untuk sedbagian itu akan menjadi sesuatu seperti head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk -1sintaks untuk headtidak portabel.
mikeserv
1

Dengan perl:

perl -e 'my @lines = <>; print for @lines[0, $#lines, 1..$#lines-1]' file

Dengan awk:

$ awk '
    {lines[NR]=$0}
    END{
        print lines[1], lines[NR];
        for (i=2; i<NR; i++) {print lines[i]}
    }
' OFS=$'\n' file

KELUARAN

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Gilles Quenot
sumber