Níže je uveden text v souboru:
Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good
Musím pozdravit „42B“ a získat výstup z výše uvedeného textu jako:
Pseudo name=Apple Code=42B state=fault
Má někdo představu, jak toho dosáhnout pomocí grep
/ awk
/ sed
?
Komentáře
- Tuto otázku jste označili pouze " grep ". Hledáte tedy pouze " grep " řešení? V otázce zadáte také awk & sed. Můžeme přidat tyto značky? Když jsem včera upravoval otázku, nebyl jsem si ' jistý svým záměrem.
- stackoverflow.com/ questions / 12024410 / …
odpověď
S awk
awk -v RS="" "/42B/" file
RS=
změní oddělovač vstupních záznamů z nového řádku na prázdné řádky. Pokud kterékoli pole v záznamu obsahuje /42B/
vytiskněte záznam.
""
(prázdný řetězec) je kouzlo hodnota použitá k vyjádření prázdných řádků podle POSIX :
If RS je null, pak jsou záznamy odděleny sekvencemi skládajícími se z
<newline>
plus jednoho nebo více prázdných řádky, úvodní nebo koncové prázdné řádky nesmí vést k prázdným záznamům na začátku nebo na konci vstupu a<newline>
musí být vždy oddělovač pole, bez ohledu na hodnotu FS je.
Výstupní odstavce nebudou být odděleny, protože oddělovač výstupu zůstává jediným novým řádkem. Abyste zajistili, že mezi výstupními odstavci bude prázdný řádek, nastavte oddělovač výstupních záznamů na dva nové řádky:
awk -v RS="" -v ORS="\n\n" "/42B/" file
Komentáře
- +1 pro elegantní řešení. Soubor však ' nemusíte přesměrovat …
- prsty byly na autopilotu.
- @jasonwryan, pokud nepotřebujete přístup na název souboru v rámci awk (
FILENAME
), ' není špatný nápad použít přesměrování, aby se předešlo problémům s názvem souboru obsahujícím=
nebo počínaje-
(nebo-
) zajišťuje konzistentní chybové zprávy a vyhne se spuštěníawk
nebo jiným přesměrováním, pokud nelze vstupní soubor ' otevřít.
Odpověď
Předpokládejme, že data jsou strukturována tak, aby vždy byly řádky před a po, které chcete. = „d01d1d6240″>
(po) a -B
(dříve) přepne a řekne mu, aby zahrnoval 1 řádek před zápasem a 1 řádek po něm:
$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
Pokud chcete stejný počet řádků před a za hledaným výrazem můžete použít -C
(kontextový) přepínač:
$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
Pokud chcete být přísnější při porovnávání více řádků, můžete použít nástroj pcregrep
a vzor na více řádcích:
$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault
Výše uvedený vzor odpovídá následovně:
-
-M
– více řádků -
"Pseudo.*\n.*42B.*\nstate.*"
– odpovídá skupině řetězců, kde první řetězec začíná slovem"Pseudo"
následovány libovolnými znaky až do konce řádku\n
, následovanými libovolnými znaky až do řetězce"42B"
následovanými libovolnými znaky až do další konec řádku (\n
), za kterým následuje řetězec"state"
následovaný libovolnými znaky.
Komentáře
- (kontext) lze použít jako zkratku, pokud
-A
a-B
jsou stejné. - @DavidBaggerman – děkuji. Přidal to do odpovědi.
- Proč ten, kdo hlasoval? To odpovídá na otázku.
Odpověď
grep
z některé příchutě Unixu mají pro „odstavec“ příznak -p
. Vím, že AIX ano .
grep -p 42B <myfile>
by tam udělal přesně to, o co tam žádáte . YMMV a GNU grep tento příznak nemají.
Komentáře
- Příznak -p by bylo skvělé. Zvláště pokud se používá společně s -v, takže můžete z výstupu vyloučit celé odstavce.
Odpověď
Existuje pravděpodobně podobně snadný způsob, jak to udělat pomocí awk, ale v perlu:
cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;"
To v zásadě znamená rozdělit soubor na bloky oddělené prázdnými řádky a potom vytisknout pouze bloky, které odpovídají vašemu regulárnímu výrazu.
Komentáře
- To lze zjednodušit použitím voleb a zkratek a ztrátou zbytečného používání
cat
;perl -00 -ne 'print if /42B/' file
odpověď
Další perlové řešení bez koncový prázdný řádek:
perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo
Example
% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good
Komentáře
- Nebo kratší (a tedy čitelnější), jak napsal triplee v komentáři:
perl -00 -ne 'print if /42B/' file
.