Удалить все комментарии, кроме последней, для каждого блока комментариев

Дайте мне знать, если это то, что вам нужно.

  • файл labels.txt, используемый для тестирования:
label_zero
label_one
label_two
label_three
label_four
  • Perl-скрипт для применения метки к каждому столбцу (до тех пор, пока они не будут исчерпаны):
echo "1 1 0 0 2 3 23101 23101 0 0 2 0 5 2 0 0" |
  perl -e 'open($lf, "<", "labels.txt");
           @lbs = <$lf>;
           chomp(@lbs);
           @cols = split(/ /, <STDIN>);
           for $i (0..$#cols) {
             printf("%s %s\n", $lbs[$i] || "label_".$i, $cols[$i])
           };'
  • выход:
label_zero 1
label_one 1
label_two 0
label_three 0
label_four 2
label_5 3
label_6 23101
label_7 23101
label_8 0
label_9 0
label_10 2
label_11 0
label_12 5
label_13 2
label_14 0
label_15 0
4
26.11.2020, 13:08
3 ответа

Очевидно, вы хотите удалить из ввода все строки комментариев, за которыми следуют другие строки комментариев. Вызов sedтерпит неудачу, потому что регулярные выражения по умолчанию "жадные" (, т.е. потребляют как можно больше ), что не может быть легко изменено.

Поэтому я добавлю основанное наawk-решение к заявленной цели:

awk '/^#/{buf=$0;next} {if (buf) {print buf; buf=""}}1' "${InputP}"

или чуть более компактный:

awk '/^#/{buf=$0;next} buf{print buf; buf=""}1' "${InputP}"
  • Это напечатает все строки, которые не являются строками комментариев без изменений. (1за пределами блоков правил означает «печатать текущую строку, включая все изменения, сделанные до сих пор» -, что в данном случае отсутствует ). ].
  • Если встречается строка комментария, (строка соответствует шаблону /^#/), содержимое будет сохранено в буфере buf, но еще не напечатано. Команда nextпропускает выполнение до следующей строки, поэтому оставшийся код применяется только к строкам комментариев, отличным от -.
  • Если встречается строка комментария, отличная от -, сначала печатается содержимое буфера (, если оно имеется ), и буфер очищается (, чтобы предотвратить множественную распечатку ), прежде чем будет напечатано фактическое содержимое строки.
7
18.03.2021, 22:47

Проблема в том, что .*является жадным, поэтому sed -z -e 's/#.*\n#/#/g'будет соответствовать от самой первой строки, содержащей #, до последней строки, начинающейся с #. Это происходит только из-за флага -z, который одновременно поглощает весь файл в пространстве шаблонов (, предполагая, что в текстовом файле нет нулевых байтов ).

Сценарий Sed для решения вашей проблемы:

sed -n '/^#/N;/\n#/D;p' file
  • /^#/NЕсли строка начинается с #, добавьте следующую строку в пространство шаблонов.
  • /\n#/DЕсли пространство шаблонов содержит новую строку, за которой следует #, удалите все до новой строки и начните новый цикл.
  • pПечать пространства шаблона при достижении этой команды.

Полезные ссылки

9
18.03.2021, 22:47

Это должно работать:

perl -ne 'print $x,$_ unless /^#/; $x = /^#/ ? $_ : ""' < infile

Я получил ожидаемый результат, который вы опубликовали.

Редактировать :объяснение

  • примите $xза $left_over_line_to_be_printed, если хотите:-)
  • Первый оператор печатает любую оставшуюся строку, затем текущую строку, если текущая строка не является строкой заголовка.
  • Второй оператор устанавливает «остаток» в последнюю видимую строку заголовка или в пустую строку. (То есть для строки заголовка НЕ ​​-«оставшейся» будет пустая строка, поскольку она уже была напечатана первым оператором. Для строки заголовка это будет строка. Если несколько строк заголовка сойдутся вместе, она окажется последней ).
1
18.03.2021, 22:47

Теги

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