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

Для LS_COLORS и ~/.dir_colors загрузка с фильтром (sed?) Вместо того, чтобы иметь "pattern color" "pattern color"... в 10 строках хотелось бы DEF_COLOR color pattern pattern pattern...в одной строке. Как sed переформатировать строку, чтобы я мог использовать

DEF_COLOR 31 .tar .tgz .zip .z .gz .bz .tbz .tbz

и получить необходимое количество строк в реальном формате файла конфигурации? Как это...

.tar 31
.tgz 31
.zip 31
.z   31
.gz  31
.bz  31
.tbz 31

5 ответов

Решение

Это то, что вы пытаетесь сделать?

$ cat file
DEF_COLOR 31 .tar .tgz .zip .z .gz .bz .tbz .tbz

$ awk '{for (i=3;i<=NF;i++) print $i, $2}' file
.tar 31
.tgz 31
.zip 31
.z 31
.gz 31
.bz 31
.tbz 31
.tbz 31

Если вы хотите сделать это только для строки, которая начинается с DEF_COLOR (единственная строка в примере, но, возможно, у вас есть другие), тогда:

awk '/^DEF_COLOR/{for (i=3;i<=NF;i++) print $i, $2}' file

Вышеупомянутое будет вести себя одинаково при использовании любого awk в любой оболочке в каждом блоке Unix, поэтому, если вы ищете решение, переносимое во все системы Unix, это оно.

Мне нравится sed, но мне это не нравится. (Он плохо справляется с разделителями полей)

Вот версия на Perl.

perl -lne '@f=split;print "$_ $f[1]" for @f[2..$#f]'

  • разбить строку на массив @f
  • использовать -l чтобы получить разрыв строки на каждом отпечатке
  • распечатать каждый элемент в @f с 3-го до последнего со 2-м элементом впоследствии

Или, как указывает @tshiono, добавьте -a чтобы получить массив автоматически:

perl -lane 'print "$_ $F[1]" for @F[2..$#F]'

В общем perl -p и perl -n перевести Perl в режим потоковой обработки, аналогичный sed и sed -n... но с гораздо большим количеством доступных инструментов.

С участием GNU sed как насчет:

echo DEF_COLOR 31 .tar .tgz .zip .z .gz .bz .tbz .tbz21 .tz .zoo .7z .rz | sed 's/ /\n/g' | sed -n '
2{h;d}           ;# save the 2nd line in hold space and delete pettern space
3,${G;s/\n/ /;p} ;# append hold space to pattern space; replace the 1st newline with a whitespace; then print pattern space

Вывод:

.tar 31
.tgz 31
.zip 31
.z 31
.gz 31
.bz 31
.tbz 31
.tbz21 31
.tz 31
.zoo 31
.7z 31
.rz 31

Как отмечает @stevesliva, я бы предпочел использовать другой язык для такого рода задач:)

       sed '/^DEF_COLOR */{ s///      ; t x ; :x
s/\([^ ]*\)  *\([^ ]*\)/\2 \1\nDEF_COLOR \1/; t ok
d
:ok ; P;D}
  1. Работайте только со строками DEF_COLOR, удалите их и пробелы и используйте t x;:x (nop), чтобы очистить флаг перехода.
  2. Затем s ///, чтобы поменять местами первые 2 слова (31 .tar -> .tar 31) для печати, но также добавить новую строку (конец печати) и снова добавить цвет DEF_COLOR, так что это все еще будет строка DEF_COLOR после \n.
    DEF_COLOR 31.tar.tgz... становится.tar 31\nDEF_COLOR 31 .tgz... и если это сработало, goto ok (пропустите d в #3)(t перескакивает, если s /// сработало, но это сработало на шаге #1 тоже, поэтому t ok;:ok там, так что t здесь проверяет, только если это s /// сработало) (этот шаг уродливый, я уверен, что есть способы получше)
  3. Если s /// не удалось (остается только цвет, без узоров), удалите все. (линия сделана)
  4. ok: смена шаблона / цвета сработала, поэтому P(печать до новой строки (цвет шаблона));D(удаление до новой строки) и начало заново (продолжайте укорачивать строку DEF_COLOR до тех пор, пока шаблоны не исчезнут)

Я уверен, что это можно улучшить, но это работает.
PS: Извините за ответ на мой вопрос. (и я думаю, что воспользуюсь решением perl)

Просто сделать это сценарием кажется лучшим ответом.

      function EXT() { for x in "$@"; do echo ".$x $COLOR"; done; }
COLOR=31 EXT tar tgz zip z gz bz tbz tbz

Чтобы ответить на вопрос, как я его задал,
DEF_COLOR 31 .tar .tgz .zip .z .gz .bz .tbz .tbz
я мог бы использовать

      function DEF_COLOR { C="$1"; shift; for x in "$@"; do echo "$x $C"; done; }
Другие вопросы по тегам