Необходимо переместить последнюю строку файла во вторую строку того же файла

8

У меня есть файл «тест» в Linux с данными ниже.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Мне нужно вырезать последнюю строку этого файла и поместить его во вторую позицию. Это должно выглядеть как ниже.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Вивек Уильям
источник

Ответы:

9

Эту проблему на самом деле проще всего решить ed, так как это текстовый редактор, а не потоковый процессор. Используя ed, вы не должны сохранить все строки файла в массив, например, так как он уже делает это для вас.

# 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
источник
5

Метод удержания буфера:

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

... это будет Hстареть каждую строку, которая !не первая, а первая она pнабирает. В $последней строке он xизменяет удержание и образует пробелы перед тем, как Hвыполнить старую процедуру, в которой сохраненные строки добавляются к последней строке, а затем dвыбирается из всех строк, которые !не являются $последними.

В $последней строке он xснова меняет пробелы, s///убирает первый \nсимвол ewline - который заботится о дополнительном добавлении в строке 2 - затем автоматически печатает лот.

ВЫВОД:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

без использования буфера Hold:

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

... просто чтобы сохранить пример в реальном файле ...

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

Который перенаправляет <infileна первый sedstdin, которые только prints первой строки перед deleting от выхода всех линий , которые !не в $последней очереди . Последняя строка autoprinted, но это также единственная линия , на которой выполняется последняя команда - которая является rEAD вне цельной infile снова к stdout. Все это передается по каналу |во вторую, sedкоторая затем должна только dвыбрать из своего выхода свою третью и последнюю строки ввода, чтобы завершить перестановку.

ВЫВОД:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
источник
круто +1. Я не помню, чтобы вы когда-либо публиковали awkрешения, вы большой sedпоклонник или, возможно, вы написали sed? ;-)
iruvar
@ 1_CR - я не знаю, как использовать awk- я никогда не пробовал. может быть, когда-нибудь ...
mikeserv
2

Наивный подход с использованием 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

Вы сохраняете каждую строку в aмассиве, затем печатаете массив в нужном вам порядке (1-я строка, последняя ( NR) и от 2 до предпоследней.

Используя комбинацию головы / хвоста и седа:

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

Выведите первую строку, последнюю, а с помощью sed удалите первую и последнюю.


Только с помощью sed мне удалось найти только эту команду. Я уверен, что есть лучшие способы:

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

Если это первая строка, выведите ее (по умолчанию).
Со второй строки поместите его в буфер удержания ( H) и удалите из пространства шаблона ( d). И если это последняя строка, напечатайте его ( p), затем получите буфер удержания ( x), удалите пустую строку ( s/^\n//) и напечатайте ее ( p).

fredtantini
источник
Моим первым инстинктом было бы использовать метод голова / хвост. Альтернативой этой sedчасти будет что-то вроде head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk -1синтаксис для headне является переносимым.
mikeserv
1

С perl:

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

С awk:

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

ВЫВОД

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Жиль Квено
источник