У меня есть требование написать сценарий оболочки в csh для поиска и удаления строк, соответствующих шаблону, вместе с комментариями в предыдущей строке, если таковые имеются. Например, если в моем файле есть следующие строки
Shell script #this is a test pattern1 format1 pattern2 format2 #format3 pattern3
Если шаблон поиска - "шаблон", результат должен быть следующим
Shell script format1 format2
Чтобы быть более точным, следует удалить строки, которые имеют шаблон, и предыдущую строку, если она начинается с "#".
Спасибо за помощь
Вот sed
версия. Некоторые версии sed
может потребоваться разделить части этого на несколько -e
статьи.
sed '$b;N;/^#.*\npattern.*$/ ! {P;D}; :c; $d; s/.*\n//;N;/^#.*\npattern.*$/ {bc}; /^pattern/d; D' patterns
Вот версия файла сценария этого однострочника с комментариями:
#!/bin/sed -f
# Search for a combination of a comment followed by a pattern
# until that, print what you find.
$b
N
/^#.*\npattern.*$/ ! {
P
D
}
:c
# Got a comment and a pattern combination in pattern space.
# At the end of the file we simply exit
$d
# Else, we keep reading lines with `N' until we
# find a different one
s/.*\n//
N
/^#.*\npattern.*$/ {
bc
}
# Remove standalone lines that have "pattern"
/^pattern/d
# Remove the last instance of the combination
# and go back to the top
D
Это основано на сценарии в info sed
раздел 4.16 «Удалить все повторяющиеся строки» (uniq -u).
Вероятно, лучший способ написать это логически, но я думаю, что это может сделать это:
#!/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
Вот однострочное решение на Perl (не в оболочке C). Вы можете изменить /pattern/
регулярное выражение посередине.
perl -ne 'if(/^#/){$c=$_}elsif(!/pattern/){print$c,$_;$c=""}else{$c=""}' <file.in
Прежде всего никто никогда не должен использовать csh
ни за что - он устаревший и неработающий (не "под"). Во-вторых, я сомневаюсь, что справится с этой задачей. В-третьих, гораздо более вероятно, что awk
, sed
или даже Perl будет гораздо лучшим инструментом для этой задачи.
awk '/^#/ {printf line; line=$0"\n"; next} /pattern/ {line=""} ! /pattern/ {printf line; print; line=""}'
Изменить: исправлен скрипт для правильной обработки строк комментариев
Это должен быть сценарий оболочки?
:g/<pattern>/d
:g/^#/d
может быть эффективно воспроизведен с помощью sed, если он должен быть написан скриптом
редактировать:
1. создать файл .sedscript:
/pattern/d
/^#/d
2.sed -f .sedscript <inputfile> > <outputfile>
Это не удовлетворяет требованию удалить предыдущую строку, но ваш пример, похоже, не требует этой функции.