sed конвертировать 4 пробела в 2


14

Как преобразовать 4 пробела в 2 пробела с помощью sed? Является ли это возможным?

Я нашел это, но он конвертирует табуляцию в пробелы:

sed -r ':f; s|^(\t*)\s{4}|\1\t|g; t f' file

Ответы:


13

Размещенный вами скрипт преобразует 4 * n пробелов в n вкладок, только если этим пробелам предшествуют только вкладки.

Если вы хотите заменить 4 пробела на 2 пробела, но только с отступом, хотя это можно сделать с помощью sed, я рекомендую вместо этого Perl.

perl -pe 's{^((?: {4})*)}{" " x (2*length($1)/4)}e' file

В седе:

sed -e 's/^/~/' -e ': r' -e 's/^\( *\)~    /\1  ~/' -e 't r' -e 's/~//' file

Вы можете использовать indentвместо этого.


Я получилNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek

1
@eddygeek Да, действительно, это и несколько других ошибок. Я заменил gobbledygook на фактический код Perl.
Жиль "ТАК - перестань быть злым"

5

Разве простой способ не работает:

sed -r 's/ {4}/  /g'

Если нет, опубликуйте информацию, если она не удалась.


1
Это не ограничивается началом строки. Если вы закрепите его там, он не будет работать для нескольких совпадений. Итак, мы находимся по адресу unix.stackexchange.com/a/375200/259620 ниже.
geek-merlin

Это не сработает, если у вас есть комбинация из 2 пробелов и 4 пробелов, потому что два отступа в два будут считаться четырьмя ...
Мэтт Флетчер

@aexl: Это не было требованием OP
Thor

@mattfletcher: вопрос был о замене 4 пробелов на 2, поэтому я не вижу вашей точки зрения
Тор,

4

Если только начальные пробелы должны быть преобразованы:

sed 'h;s/[^ ].*//;s/    /  /g;G;s/\n *//'

С комментариями:

sed '
  h; # save a copy of the pattern space (filled with the current line)
     # onto the hold space
  s/[^ ].*//; # remove everything starting with the first non-space
              # from the pattern space. That leaves the leading space
              # characters
  s/    /  /g; # substitute every sequence of 4 spaces with 2.
  G; # append a newline and the hold space (the saved original line) to
     # the pattern space.
  s/\n *//; # remove that newline and the indentation of the original
            # line that follows it'

Также посмотрите на 'ts'настройки и :retabкоманды vim


Используя ваше решение vim, есть ли способ пакетного редактирования нескольких файлов с помощью vim? В противном случае я предполагаю, что мне придется создать макрос?
Chrisjlee

Обратите внимание, что 'ts'и :retabне являются решением вопроса, но связаны и могут помочь в достижении вашей общей цели. Вы можете сделать vim -- *.c, :set ts=...а затем :argdo retabили :argdo retab!. Смотрите также 'sw'опцию и собственные возможности отступов vim.
Стефан Шазелас

2
sed 's/^\( \+\)\1\1\1/\1\1/' file

Он работает, разделяя ведущие пробелы на четыре экземпляра одной и той же группы (чтобы они все были равны), а затем заменяя их только двумя экземплярами группы.


Как это улучшает существующие решения?
Филиппос

1
Он сохраняет нечетные пробелы, влияет только на начальные пробелы, не требует глобального флага, легко настраивается для обработки любого количества пробелов (или табуляции) с обеих сторон замены и не использует более сложные команды sed, которые может быть отталкивающим для более случайных пользователей. Как и во многих других вещах, является ли это улучшение довольно субъективным, но я говорю за себя: найти его в сценарии было бы значительно проще, чем некоторые другие перечисленные решения.
Мал

Интересный. Рад, что я спросил. Обычно обратные ссылки считаются злом, а не глобальным флагом. Но вы могли бы легко добиться того же с помощью более переносимого скрипта (избегая \+). Спасибо.
Филиппос

1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

Это должно только сжать ведущие последовательности пробелов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.