Искать и удалять строки, соответствующие шаблону, вместе с комментариями в предыдущей строке, если таковые имеются.

Вопрос или проблема

У меня есть задача написать shell-скрипт на csh для поиска и удаления строк, соответствующих шаблону, вместе с комментариями в предыдущей строке, если таковые имеются. Например, если мой файл содержит следующие строки

Shell script
#это тест
pattern1
format1
pattern2
format2
#format3
pattern3

Если шаблон поиска – “pattern”, то вывод должен быть следующим

Shell script
format1
format2

Чтобы быть более точным, строки, которые содержат шаблон, и предыдущая строка, если она начинается с “#”, должны быть удалены

Спасибо за помощь

Прежде всего, никто никогда не должен использовать csh для чего-либо – это устарело и неэффективно. Во-вторых, я сомневаюсь, что он справится с этой задачей. В-третьих, гораздо более вероятно, что awk, sed или даже Perl будут гораздо лучшим инструментом для этой задачи.

awk '/^#/ {printf line; line=$0"\n"; next} /pattern/ {line=""} ! /pattern/ {printf line; print; line=""}'

Редактировать: исправлен скрипт для корректной обработки строк-комментариев

Вот однострочное решение на Perl (не на C shell). Вы можете изменить регулярное выражение /pattern/ в середине.

perl -ne 'if(/^#/){$c=$_}elsif(!/pattern/){print$c,$_;$c=""}else{$c=""}' <file.in

Наверное, более лучший способ логически записать это, но я думаю, это может сработать:

#!/usr/bin/perl
use strict;
use warnings;

my $previous_line="";
while(<>) {
    if ( /pattern/ ) {
        if ( (! ($previous_line =~ /^#/)) && (! ($previous_line =~ /pattern/))) {
            print $previous_line;
        }
    } elsif (! ($previous_line =~ /pattern/)) {
        print $previous_line;
    }
    $previous_line = $_;
}
print $previous_line if not ($previous_line =~ /pattern/);

По сути, цикл на одну строку позади с предыдущей строкой. Он говорит, что можно напечатать предыдущую строку, если:

  1. Если текущая строка соответствует шаблону: можно напечатать предыдущую, если предыдущая строка также не соответствует шаблону или это не комментарий.
  2. Если эта строка не соответствует шаблону, можно напечатать предыдущую строку, если она не соответствовала шаблону.

Вы можете просто сохранить код в файл и использовать его так: perl thefile.pl textfile_you_want_to_filter

Вот версия на sed. Некоторые версии sed могут требовать, чтобы части этого были разделены на несколько клауз.

sed '$b;N;/^#.*\npattern.*$/ ! {P;D}; :c; $d; s/.*\n//;N;/^#.*\npattern.*$/ {bc}; /^pattern/d; D' patterns

Вот версия скрипта этого однострочного кода с комментариями:

#!/bin/sed -f

# Ищем комбинацию комментария, за которой следует шаблон
# до этого печатаем то, что находим.
$b
N
/^#.*\npattern.*$/ ! {
P
D
}

:c
# У нас есть комбинация комментария и шаблона в пространстве шаблонов.
# В конце файла мы просто выходим
$d

# В противном случае продолжаем читать строки с помощью `N`, пока не
# найдем другую
s/.*\n//
N
/^#.*\npattern.*$/ {
bc
}

# Удаляем отдельные строки, которые содержат "pattern"
/^pattern/d

# Удаляем последний экземпляр комбинации
# и возвращаемся к началу
D

Это основано на скрипте в info sed секция 4.16 “Удалить все дублированные строки” (uniq -u).

Обязательно ли это скрипт на shell?

  1. открыть файл с помощью vi
  2. :g/<pattern>/d
  3. повторять по мере необходимости для дополнительных
    типов шаблонов, если вы не можете использовать регулярное выражение
    для шаблона
  4. :g/^#/d

можно эффективно воспроизвести с помощью sed, если это должно быть скриптом

редактировать:

1. создать файл .sedscript:

/pattern/d
/^#/d

2. sed -f .sedscript <inputfile> > <outputfile>

Это не удовлетворяет требованию удалить предыдущую строку, но ваш пример, похоже, не требует этой функции.

Ответ или решение

Удаление строк, соответствующих шаблону, вместе с комментариями в предыдущих строках: Руководство по написанию скрипта на C Shell

В современном программировании и администрировании систем часто возникает необходимость в эффективном управлении текстовыми файлами. Задача, которую мы рассмотрим, включает удаление строк, соответствующих определенному шаблону, а также комментариев в предыдущих строках, если таковые имеются. В этом руководстве мы сосредоточимся на создании скрипта на C Shell (csh) для решения этой задачи.

Проблема

У вас есть файл, содержащий текстовые строки и потенциальные комментарии. Например, в вашем файле могут быть следующие строки:

Shell script
#this is a test
pattern1
format1
pattern2
format2
#format3
pattern3

Если вы ищете строки, содержащие "pattern", необходимо удалить как сами эти строки, так и любой комментарий на строке выше, если он существует, чтобы получить на выходе:

Shell script
format1
format2

Решение с использованием C Shell

C Shell не всегда считается самым подходящим инструментом для обработки текстов, однако, если ваша задача требует использования именно этого языка, вот пример скрипта для достижения нужного результата:

#!/bin/csh

set file = "input.txt"  # Укажите название вашего файла
set pattern = "pattern"  # Задайте искомый шаблон
set prev_line = ""  # Хранит предыдущую строку

# Открываем файл для чтения
cat $file | while read line
  if ("$line" =~ "$pattern") then
    # Если текущая строка соответствует шаблону,
    # ничего не выводим и сбрасываем предыдущую строку
    set prev_line = ""
  else if ("$prev_line" =~ "#*" && "$prev_line" != "") then
    # Если предыдущая строка является комментарием,
    # сбрасываем ее и не выводим
    set prev_line = ""
  else
    # Если предыдущая строка не комментарий и не соответствует шаблону, выводим ее
    if ("$prev_line" != "") then
      echo $prev_line
    endif
    set prev_line = $line  # Обновляем значение предыдущей строки
  endif
end

# Выведем последнюю строку, если она не совпадает с шаблоном и не является комментарием
if ("$prev_line" != "" && !("$prev_line" =~ "$pattern" || "$prev_line" =~ "#*")) then
  echo $prev_line
endif

Пояснение работы скрипта

  1. Инициализация переменных: Скрипт устанавливает переменные для хранения имени файла и искомого шаблона. Переменная prev_line используется для хранения предыдущей строки при чтении файла.

  2. Чтение файла: Скрипт использует команду cat для вывода содержимого файла и while для построчного чтения.

  3. Логика удаления:

    • Если текущая строка содержит шаблон, она игнорируется.
    • Если предыдущая строка является комментарием и не пуста, она также игнорируется.
    • Если предыдущая строка не соответствует шаблону, и не является комментарием, она выводится на экран.
  4. Вывод окончательной строки: После завершения чтения, последний обработанный элемент выводится, если он не является комментарием или не совпадает с шаблоном.

Заключительные мысли

Хотя C Shell может быть использован для выполнения данной задачи, я настоятельно рекомендую рассмотреть альтернативы, такие как sed или awk, которые более удобны и функциональны для текстовой обработки. Эти инструменты позволяют более эффективно реализовать подобные задачи с меньшими усилиями и более понятным синтаксисом.

Тем не менее, для минимального объема работы или в специфических случаях, когда использование C Shell необходимо, приведенный выше скрипт справится с поставленной задачей.

Оцените материал
Добавить комментарий

Капча загружается...