Jak wybrać linie pomiędzy dwoma wzorcami znaczników, które mogą wystąpić wielokrotnie w awk / sed
Używając awk
lub sed
Jak wybrać linie, które występują pomiędzy dwoma różnymi wzorami znaczników? Może być wiele sekcji oznaczonych tymi wzorami.
Na przykład: Załóżmy, że plik zawiera:
abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu
I wzorzec początkowy to {[5] } a wzorzec końcowy to mno
Więc potrzebuję wyjścia jako:
def1
ghi1
jkl1
def2
ghi2
jkl2
Używam sed do dopasowania wzorca raz:
sed -e '1,/abc/d' -e '/mno/,$d' <FILE>
Czy jest jakiś sposób w sed
lub awk
aby robić to wielokrotnie aż do końca pliku?
8 answers
Użyj awk
z flagą, aby wywołać wydruk w razie potrzeby:
$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2
Jak to działa?
-
/abc/
dopasowuje linie zawierające ten tekst, podobnie jak/mno/
. -
/abc/{flag=1;next}
ustawiaflag
gdy tekstabc
zostanie znaleziony. Potem omija linię. -
/mno/{flag=0}
usuwaflag
, gdy tekstmno
zostanie znaleziony. - finalny
flag
jest wzorcem z domyślną akcją, którą jestprint $0
: Jeśli {[5] } jest równe 1, drukowana jest linia.
Dla bardziej szczegółowy opis i przykłady, wraz z przypadkami, gdy wzory są wyświetlane lub nie, zobacz Jak wybrać linie między dwoma wzorami?.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:56
Używając sed
:
sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'
Opcja -n
oznacza domyślnie nie Drukuj.
Wzorzec wyszukuje linie zawierające tylko abc
do tylko mno
, a następnie wykonuje akcje w { ... }
. Pierwsza akcja usuwa linię abc
, druga linię mno
, A p
wyświetla pozostałe linie. Możesz rozluźnić wyrażenia regularne w razie potrzeby. Dowolne linie spoza zakresu abc
..mno
po prostu nie są drukowane.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 08:47:40
To może zadziałać dla Ciebie (GNU sed):
sed '/^abc$/,/^mno$/{//!b};d' file
Usuń wszystkie linie z wyjątkiem tych pomiędzy liniami rozpoczynającymi się abc
i mno
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 09:39:57
sed '/^abc$/,/^mno$/!d;//d' file
Golfs two characters better than ppotong ' s {//!b};d
Puste ukośniki //
oznaczają: "użyj ponownie ostatniego użytego wyrażenia regularnego". a polecenie robi to samo co bardziej zrozumiałe:
sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file
This seems to be POSIX :
Jeśli RE jest pusty (tzn. nie podano wzorca) sed zachowuje się tak, jakby ostatnia RE użyta w ostatnio zastosowanym poleceniu (jako adres lub jako część polecenia zastępczego) była określone.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33
Z linków poprzedniej odpowiedzi wynika, że ten, który zrobił to dla mnie, uruchamiając ksh na Solarisie, był taki:
sed '1,/firstmatch/d;/secondmatch/,$d'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-12 16:38:10
ODPOWIEDŹ Don_crissti z pokazuje tylko tekst pomiędzy 2 pasującymi wzorami?
firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile
Który jest znacznie bardziej wydajny niż aplikacja AWK, zobacz Tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 12:36:28
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 09:13:08
Coś takiego działa u mnie:
Plik.awk:
BEGIN {
record=0
}
/^abc$/ {
record=1
}
/^mno$/ {
record=0;
print "s="s;
s=""
}
!/^abc|mno$/ {
if (record==1) {
s = s"\n"$0
}
}
Używając: awk -f file.awk data
...
Edit: O_o fedorqui rozwiązanie jest o wiele lepsze/ładniejsze niż moje.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-11 11:32:58