Изменить порядок строк в файле

В настоящее время нет расширение, которое может предоставить эту функциональность. Но есть один, который может помочь вам организовать ваши рабочие пространства, если он совместим с вашей версией оболочки GNOME, «Сетка рабочего пространства»:

https://extensions.gnome.org/extension/484/workspace-grid/

​​

11
01.06.2017, 01:25
9 ответов

Используя awk и целочисленную математику:

awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input

Оператор модуля выполняет целочисленное деление и возвращает остаток, поэтому для каждой строки он возвращает последовательность 1, 2, 0, 1, 2, 0. [...]. Зная это, мы просто сохраняем ввод в строках, где модуль равен 2, на потом — то есть сразу после печати ввода, когда он равен нулю.

12
27.01.2020, 19:56

Использование: ./shuffle_lines.awk input.txt

Check shebang #!/usr/bin/awk -f, потому что awk может отличаться в вашей системе.

#!/usr/bin/awk -f

{
    if ((NR + 1) % 3 == 0) {
        buffer = $0;
    } else if (NR % 3 == 0) {
        print $0 ORS buffer;
        buffer = "";
    } else {
        print;
    }
}
0
27.01.2020, 19:56

Другой awk подход:

awk '{print $0; if ((getline L2)>0 && (getline L3)>0){ print L3 ORS L2 }}' file

Вывод:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

  • (getline L2)>0 && (getline L3)>0 - извлечения следующие 2 записи, если они существуют

  • каждая 2-я и 3-я записи назначаются переменным L2 и L3 соответственно

3
27.01.2020, 19:56

Почему бы просто не сделать цикл while? В развернутом виде:

( while read a
  do
    read b
    read c
    echo "$a"
    echo "$c"
    echo "$b"
  done
) < input.txt

В "однострочном формате":

( while read a ; do read b ; read c ; echo "$a" ; echo "$c" ; echo "$b" ; done) < input.txt

Выходы:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
1
27.01.2020, 19:56

Один из способов может быть следующим:

sed -e '
   /\n/s/\(.*\)\(\n\)\(.*\)/\3\2\1/;//b
   $!N;$q;N;                            # load up the pattern space with 3 lines provided eof not reached
   P;D;                                 # first just print the first line then interchange the two and print them
' yourfile

В качестве альтернативы,

perl -ne 'print $_, reverse scalar <>, scalar <>' yourfile

Результаты

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
1
27.01.2020, 19:56

Vim

Не подходит для длинных файлов, но все же удобен, если вы просто редактируете файл и хотите, например, изменить порядок некоторых строф yaml.

Сначала запишите макрос:

gg qq j ddp j q

Затем повторите нужное количество раз:

@q @q @q ...

Или просто, например.

3@q

Объяснение:

  • gg - перейти на первую строку
  • qq - начать запись макроса
  • j - перейти на вторую строку
  • ddp - поменять местами вторую и третью строку
  • j - перейти к четвертой строке, т.е. к первой из следующих трех строк
  • q - остановить запись
  • @q - воспроизвести макрос один раз
  • 3@q - воспроизвести макрос три раза
1
27.01.2020, 19:56

Использование perlи короткого скрипта:

user@pc:~$ cat input.txt 
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt 
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

Сценарий обрабатывает весь файл, для каждой строки (, хранящейся в $_), он получает следующие две строки($l2и$l3)и печатает их в запрошенном порядке :строка1, строка3, строка2.

1
27.01.2020, 19:56
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8

То есть, pнапечатать текущую строку, получить nдополнительную, hстарую, получить nдополнительную, Gи удерживаемую строку (добавить ее к пространство шаблонов )и pзаменяют это пространство шаблона из 2 -строк с перестановкой третьей и второй строк.

23
27.01.2020, 19:56

Перл

perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_. $var if $.%3==0' input.txt

Идея здесь в том, что мы используем оператор по модулю %с переменной номер строки $., чтобы выяснить, какая из них является каждой первой, какая — каждой второй, а какая — каждой третьей строкой. Для каждой 3-й строки остаток равен 0, а для каждой 1-й и 2-й строки будут соответствующие числа.

Тест:

$ cat input.txt                                                                                                          
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_. $var if $.%3==0' input.txt                                    
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

Незначительное улучшение

Подход с сохранением второй строки в переменной имеет изъян. Что, если последняя строка является «второй», т.е. для этого номера строки остаток равен 2 ? Исходный код в моем ответе и ответе DopeGhoti не будет печатать My dog is orange, если мы опустим последнюю строку. Исправление для этого в обоих случаях заключается в использовании блока кода END{}со сбросом временной переменной после печати. Другими словами:

$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt

и

$ perl -ne '$s=$_ if $.%3==2;print $_. $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt 

Таким образом, код будет работать для произвольного количества строк в файле, а не только для тех, которые делятся на 3.

Дополнительное исправление для проблемы, упомянутой в комментариях

В случае awk, если последняя строка в файле выводит 1 вместо $. % 3, в предыдущем коде возникла проблема с выводом пустой новой строки из-за безусловной печати END{print delay}, поскольку функция print, упомянутая в комментариях, всегда добавляет новую строку к любой переменной, над которой она работает. В случае версии perlэтой проблемы не возникает,поскольку с флагами -neфункция printне добавляет новую строку.

Тем не менее, исправление в случае awk состоит в том, чтобы сделать условие, как упоминал Dope Ghoti в комментариях, чтобы проверить длину временной переменной. Perl-версия того же исправления будет:

$ perl -ne '$s=$_ if $.%3==2;print $_. $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt 
1
27.01.2020, 19:56

Теги

Похожие вопросы