объединить команды sed, которые переключают порядок строк в файле, с помощью bash - PullRequest
0 голосов
/ 16 мая 2019

У меня есть повторяющиеся команды sed, которые переключают строки 1 и 2, 3 и 4 и т. Д. Я хотел бы объединить эти команды в одну команду sed. Однако, когда я пытаюсь объединить их, это добавляет дубликаты строк и удаляет некоторые строки.

Edit:

Порядковый номер файла до появления sed выглядит так:

Some code....
Some code...
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
some more...
some more...

Код, который дает желаемый результат:

sed -i '2{h;d};3{p;x}' file.txt && sed -i '4{h;d};5{p;x}' file.txt && sed -i '6{h;d};7{p;x}' file.txt 

Код, который я хотел бы использовать:

sed -i '2{h;d};3{p;x};4{h;d};5{p;x};6{h;d};7{p;x}' file.txt

С желаемым выводом из упорядоченного файла

Some code...
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
some more...
some more...

Ответы [ 4 ]

4 голосов
/ 16 мая 2019

Это совершенно неуместное задание для sed.Просто используйте awk, например, с GNU awk для редактирования «на месте», так как это почему-то является приоритетом, и используйте измененный пример входного файла, чтобы было ясно, какие строки поменялись местами, а какие нет:

$ cat file
with a some code here
and a some code there
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
here a code, there a code
everywhere a code, code

$ awk -i inplace 'NR>=3 && NR<=8{if ((++c)%2) p=$0; else print $0 ORS p; next} 1' file

$ cat file
with a some code here
and a some code there
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
here a code, there a code
everywhere a code, code

Кроме синтаксического сахара -i inplace только для GNU вместо > tmp && mv tmp file, скрипт будет работать с использованием любого awk в любой оболочке на любом компьютере UNIX.


Исходный ответ и другие примеры ниже:

$ awk 'NR%2{p=$0;next} {print $0 ORS p}' file
Some code...
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e

Вышеприведенное будет работать при использовании любого awk в любой оболочке на любом компьютере UNIX.

Хотите поменять местами только строки 4 и 7, скажем?Это тривиальная настройка, потому что это правильный инструмент для работы :

$ seq 10 | awk 'NR<=3 || NR>=8{print; next} (++c)%2{p=$0;next} {print $0 ORS p}'
1
2
3
5
4
7
6
8
9
10

или, если вы предпочитаете:

$ seq 10 | awk 'NR>=4 && NR<=7{if ((++c)%2) p=$0; else print $0 ORS p; next} 1'
1
2
3
5
4
7
6
8
9
10

Хотите повернуть каждые 3 строки?Опять же, тривиально, потому что это правильный инструмент для работы :

$ seq 9 | awk 'NR%3{p2=p1;p1=$0;next} {print $0 ORS p1 ORS p2}'
3
2
1
6
5
4
9
8
7

Надеюсь, вы получите картину ...

4 голосов
/ 16 мая 2019

Если вы используете GNU sed, ( $! ), если текущая строка не является последней строкой в ​​файле, ( x ) поменяйте местами пространство шаблонов и пространство хранения, ( n ) считывает новую строку в пространство образца, ( G ) добавляет содержимое пространства удержания к пространству образца с помощью перевода строки. ( p ) Печать содержимого пространства шаблона.

$ cat file
one
two
three
four
five
six
seven
$
$ sed -n -i '$!{x;n;G};p' file
$
$ cat file
two
one
four
three
six
five
seven

Чтобы сделать его полностью совместимым с POSIX, вам нужно отказаться от редактирования на месте и разбить скрипт на несколько команд:

sed -n -e '$!{x;n;G;}' -e 'p' file

Это отвечает первая версия вопроса ОП . Так как с их последними правками это стало невозможно расшифровать, я отказываюсь редактировать.

2 голосов
/ 16 мая 2019

Это может сработать для вас (GNU sed):

sed '3,8{N;s/\(.*\)\n\(.*\)/\2\n\1/}' file

Для диапазона строк добавьте следующую строку и, используя сопоставление с образцом, поменяйте их местами.

Если вы хотите поменять местами, скажем, строки 3-4 и 7-8 используйте:

sed '3ba;7ba;b;:a;N;s/\(.*\)\n\(.*\)/\2\n\1/' file

Или поменяйте местами строки 3-5 и 6-8, используйте:

sed '3,8{N;N;s/\(.*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/} file
1 голос
/ 16 мая 2019

Существует, возможно, более простое решение GNU sed 1 для этой проблемы:

1,2b   # In the range 1,2 ...
9,$b   # ... and also in 9,$, auto print and end this cycle.
3~2 {  # From line 3 and every second line thereafter,
  h    # hold, then
  d    # delete, and end this cycle.
}
G      # On every other line, append hold space and auto print.

Тестирование:

# test.sh

cat > FILE <<EOF
Some code....
Some code...
Line-a
Line-b
Line-c
Line-d
Line-e
Line-f
Some more code...
Some more code...
EOF

sed '1,2b; 9,$b; 3~2{h;d}; G' FILE

Вывод:

Some code....
Some code...
Line-b
Line-a
Line-d
Line-c
Line-f
Line-e
Some more code...
Some more code...

Обратите внимание, что выбор строк с помощью first~step, например, 3~2, является расширением GNU.

Это основано на общем примере замены строк в гл.6 из O'Reilly sed & awk 2nd ed.


1 Но я согласен с комментариями Эда Мортона о том, что AWK лучше подходит для этой проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...