Вопрос или проблема
У меня есть задача написать 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/);
По сути, цикл на одну строку позади с предыдущей строкой. Он говорит, что можно напечатать предыдущую строку, если:
- Если текущая строка соответствует шаблону: можно напечатать предыдущую, если предыдущая строка также не соответствует шаблону или это не комментарий.
- Если эта строка не соответствует шаблону, можно напечатать предыдущую строку, если она не соответствовала шаблону.
Вы можете просто сохранить код в файл и использовать его так: 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?
- открыть файл с помощью vi
:g/<pattern>/d
- повторять по мере необходимости для дополнительных
типов шаблонов, если вы не можете использовать регулярное выражение
для шаблона :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
Пояснение работы скрипта
-
Инициализация переменных: Скрипт устанавливает переменные для хранения имени файла и искомого шаблона. Переменная
prev_line
используется для хранения предыдущей строки при чтении файла. -
Чтение файла: Скрипт использует команду
cat
для вывода содержимого файла иwhile
для построчного чтения. -
Логика удаления:
- Если текущая строка содержит шаблон, она игнорируется.
- Если предыдущая строка является комментарием и не пуста, она также игнорируется.
- Если предыдущая строка не соответствует шаблону, и не является комментарием, она выводится на экран.
-
Вывод окончательной строки: После завершения чтения, последний обработанный элемент выводится, если он не является комментарием или не совпадает с шаблоном.
Заключительные мысли
Хотя C Shell может быть использован для выполнения данной задачи, я настоятельно рекомендую рассмотреть альтернативы, такие как sed
или awk
, которые более удобны и функциональны для текстовой обработки. Эти инструменты позволяют более эффективно реализовать подобные задачи с меньшими усилиями и более понятным синтаксисом.
Тем не менее, для минимального объема работы или в специфических случаях, когда использование C Shell необходимо, приведенный выше скрипт справится с поставленной задачей.