пропустить шаблон в седе - PullRequest
1 голос
/ 12 марта 2020

Я написал корректно работающий скрипт sed, который заменяет несколько пробелов одним пробелом между токенами (пропускает строки с # или //):

#!/bin/sed -f
/.*#/ !{
/\/\//n
# handle more than one space between tokens
s/\([^ ]\)\s\+/\1 /g
}

Я запускаю его в Ubuntu как this: ./spaces.sed < spa.txt

spa.txt:

/**      spa.txt      text
 date :      some date
 hih+jjhh   jgjg
 if   ( hjh>=hjhjh  )
y     **/
#   this is a comment
   //    this is a comment
lines     begins   here   ;
/****** this    line   is comment      ****/
some    more     lines
//    again comment
more     lines    words
   /**  again multi     line co
   mmment    it
comment     line
      follows   till    here**/
file    ends

Теперь я хочу добавить функциональность, позволяющую сценарию пропускать строки между шаблоном (шаблон может быть распределен в несколько строк). Это шаблон: /* и */

Я пробовал много вещей, но безрезультатно:

#!/bin/sed -f
/.*#/ !{
/\/\*/,/\*\// {
        /\/\*/n #it skips successfully the /* line
        n #also skips next line
        /\*\// !{
        }
}
/\/\//n
# handle more than one space between tokens
s/\([^ ]\)\s\+/\1 /g
}

, но скрипт не работает должным образом.

Ожидаемый результат:

/**      spa.txt      text
 date :      some date
 hih+jjhh   jgjg
 if   ( hjh>=hjhjh  )
y     **/
#   this is a comment
   //    this is a comment
lines begins here ;
/****** this    line   is comment      ****/
some more lines
//    again comment
more lines words
   /**  again multi     line co
   mmment    it
comment     line
      follows   till    here**/
file ends

предложения? Спасибо

1 Ответ

2 голосов
/ 12 марта 2020

Я бы немного переработал скрипт, чтобы обрабатывать комментарии # и // самостоятельно. С комментариями /* … */ вам придется иметь дело с однострочными и многострочными вариантами отдельно. Я также использовал бы обозначение [[:space:]] для выделения пробелов или табуляций. Я предпочитаю избегать обратной косой черты (отвращение, вызванное работой с troff во времена моей юности - если вам никогда не требовалось 16 обратных косых черт подряд, чтобы получить желаемый эффект, вы недостаточно пострадали), поэтому я использую \%…%, чтобы выбрать % символ в качестве маркера поиска вместо / (что означает, что нет необходимости экранировать косые черты в шаблоне с обратной косой чертой sh), и я использую [*] вместо \*. Запись { p; d; } печатает текущую строку, а затем удаляет ее и переходит на следующую строку. (Использование n добавляет следующую строку к текущей строке; это не то, что вам нужно.). Вторая точка с запятой не требуется для GNU sed, но для BSD (macOS) sed. Пробелы в этих скобках являются необязательными, но облегчают чтение.

Если сложить это вместе, у вас может быть spaces.sed, например:

#!/bin/sed -f

# Comments with a #
/#/ { p; d; }
# Comments with //
\%//% { p; d; }

# Single line /* ... */ comments
\%/[*].*[*]/% { p; d; }
# Multi-line /* ... */ comments
\%/[*]%,\%[*]/% { p; d; }

s/\([^[:space:]]\)[[:space:]]\{2,\}/\1 /g

В ваших данных примера (спасибо, что включили это!), это производит:

/**      spa.txt      text
 date :      some date
 hih+jjhh   jgjg
 if   ( hjh>=hjhjh  )
y     **/
#   this is a comment
   //    this is a comment
lines begins here ;
/****** this    line   is comment      ****/
some more lines
//    again comment
more lines words
   /**  again multi     line co
   mmment    it
comment     line
      follows   till    here**/
file ends

Это выглядит так, как вы хотели.

Ограничения

  • Он не удаляет несколько пробелов в начало строки.

            the leading blanks are not removed.
    
  • Если у вас есть строка с несколькими пробелами и // или #, несколько пробелов остаются:

    these     spaces    // survive
    so        do        # these
    
  • Если у вас есть несколько однострочных комментариев в одной строке, между ними не будет пробелов:

    /* these */  spaces  are   not   /* removed */
    
  • Если у вас есть однострочный комментарий и начало многострочного комментария на одной строке, многострочный комментарий не заметен. Точно так же, если у вас есть многострочный комментарий, который заканчивается строкой, а после него начинается однострочный комментарий, то если между концом одного комментария и началом следующего есть несколько пробелов, они не обработано.

    /* this */  is  not  /* handled
    very  well  */    nor   are   these   /* spaces */
    
  • Это не касается тонкостей backsla sh -newline в середине символа начального или конечного комментария, а также backsla sh - перевод строки в конце комментария //. Только мертвые программы (или программисты) дают такие комментарии, так что это не должно быть реальной проблемой. К счастью, вы не пишете компилятор; те имеют дело с ерундой. И не начинайте меня с триграфов!

  • Он не обрабатывает комментируемые последовательности внутри строк (или константы из нескольких символов):

    "/* this is not a comment */"
    '/*',   '  ',   '*/'
    

Тем не менее, большинство из этих проблем достаточно тонкие, так что вы, вероятно, в порядке, не решая их. Если вам нужно разобраться с ними, вам нужна программа, а не скрипт sed (при условии, что вы цените свое здравомыслие).

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