Похоже на ваше "чистое решение":
sed -e '1,/HI_THERE/d' input_file
Первая строка в файле — это строка 1 -специального ^
адреса нет, потому что вы всегда это знаете, в то время как $
нужен в конце, потому что вы не (обязательно )знаете какая это линия.
Это происходит, если совпадающая строка является первой строкой файла. С GNU sed вы можете использовать 0
вместо 1
, чтобы справиться с этим. Для POSIX sed и для переносимости (, которые кажутся разными в данном случае )это более сложно (см. комментарии ниже и этот последующий -вопрос).
Если вы хотите придерживаться Posix sed, вы можете использовать это:
sed -ne '
/HI_THERE/!d
:loop
n
p
bloop
' inp.file
Или в сжатой форме:
sed -n '/HI_THERE/!d;:a;n;p;ba' inp.file
$ perl -ne 'print if 1 <(/HI_THERE/...eof)' input_file
Где мы используем оператор диапазона ...
, чтобы сформировать правильный диапазон и дополнительно ограничить его, чтобы отклонить первый элемент в выбранном диапазоне.
В sed нет простого способа сделать то, что вы просите.
Самое простое переносимое POSIXly-решение для sed — что-то вроде:
sed -ne '/HI/{:1' -e 'n;p;b1' -e '}'
Другими простыми решениями являются:
sed '0,/HI/d' ./file # GNU sed
awk 'f; /HI/{f=1}'./file
Ближайшее решение POSIXly non -sed — это ed
. Просто удалите диапазон от первой строки файла до регулярного выражения /HI/
, даже если HI
находится в той же первой строке.
printf '%s\n' 1,/HI/d,p Q | ed -s file
Или
ed -Gs imfile2 <<-\edscript
1,/HI/d
,p
Q
edscript
Что означает:
-s
file
до регулярного выражения/HI/
(1,/HI/d
). ,p
). Q
).Если вы хотите изменить файл, замените ,p Q
простоw
(и запишите в файл ).
sed
не работает на 1,/HI/d, а ed
работает? Потому что sed
ожидает совпадения регулярного выражения на следующей строке.
В ed
либо 3,3
3,/3/
/3/,3
/3/,/3/
, либо3,3
3,/3/
/3/,3
/3/,/3/
будет напечатано только одно 3:
$ printf '%s\n' 3,3p 3,/3/p /3/3p /3/,/3/p Q | ed -s <(seq 5)
3
3
3
3
Пока этим занимается sed:
$ sed -ne 3,3p <(seq 5)
3
$ sed -ne 3,/3/p <(seq 5)
3
4
5
$ sed -ne /3/,3p <(seq 5)
3
$ sed -ne /3/,/3/p <(seq 5)
3
4
5
Ожидается, что регулярное выражение в конце диапазона будет соответствовать строке , следующей за строкой, соответствующей началу диапазона (слева от,
). Нет 3
следующей за строкой с номером 3
, поэтому sed печатает все следующие строки(4
и5
).
Вот почему GNU sed решает проблему с помощью 0,/HI/
.
:1;n;p;b1
? Способ печати всех строк (, кроме первой )диапазона, заключается в использовании цикла, который сначала запрашивает следующую строку, а , а затем печатает ее:
$ sed -n '5{:1;n;p;b1}' <(seq 8) # GNU syntax
6
7
8
Итак, просто сопоставьте нужное регулярное выражение /HI/
и войдите в такой цикл.
sed -n '/HI/{:1;n;p;b1}' file # GNU syntax
Который необходимо расширить до более сложного сценария, потому что некоторые старые sed не позволяют завершить labels
с помощью ;
.
sed -n -e '/HI/{:1' -e 'n;p;b1' -e '}' file # portable syntax
grep -nw HI_THERE file.txt |awk -F":" '{print $1}' | xargs -I % sed '1,%d' file.txt
Объяснение :Я grep использую точное слово w
, получаю номер строкиn
Затем я вытаскиваю номер строки с помощью awk, разделитель:
Далее я передаю это с помощью xargs и удаляю до тех пор.
sed предназначен для выполнения s/old/new для отдельных строк, вот и все. Для чего-либо еще вы должны использовать awk, например. с любым awk в любой оболочке на каждом компьютере UNIX и обработкой «HI _THERE» в любой строке:
$ awk 'f; /HI_THERE/{f=1}' file
lemon
coconut
orange
Если вы хотите использовать GNU sed для -i
, используйте вместо этого GNU awk для -i inplace
. См.https://stackoverflow.com/a/17914105/1745001для других скриптов для выбора разделов файлов.