Próbowałem znaleźć sposób na odfiltrowanie wiersza zawierającego słowa „cytryna” i „ryż”. Wiem, jak znaleźć „cytrynę” lub „ryż”, ale nie dwa z nich. Nie muszą znajdować się obok siebie, tylko jeden wiersz tekstu.
Próbowałem znaleźć sposób na odfiltrowanie wiersza zawierającego słowa „cytryna” i „ryż”. Wiem, jak znaleźć „cytrynę” lub „ryż”, ale nie dwa z nich. Nie muszą znajdować się obok siebie, tylko jeden wiersz tekstu.
Odpowiedzi:
„Oba w tej samej linii” oznaczają „ryż”, po których następują losowe znaki, po których następuje „cytryna” lub odwrotnie.
W wyrażeniu regularnym czyli rice.*lemon
lub lemon.*rice
. Możesz to połączyć za pomocą |
:
grep -E 'rice.*lemon|lemon.*rice' some_file
Jeśli chcesz użyć normalnego wyrażenia regularnego zamiast rozszerzonych ( -E
), potrzebujesz odwrotnego ukośnika przed |
:
grep 'rice.*lemon\|lemon.*rice' some_file
Aby uzyskać więcej słów, które szybko stają się nieco dłuższe i zwykle łatwiej jest używać wielu wywołań grep
, na przykład:
grep rice some_file | grep lemon | grep chicken
grep rice
znajduje wiersze zawierające rice
. Jest karmiony, w grep lemon
którym znajdą się tylko linie zawierające cytrynę ... i tak dalej. Podczas gdy PO - podobnie jak poprzednie odpowiedzi - zezwala na każdy z [ryż | cytryna | kurczak]
|
trzeba uciekać grep
? Dzięki!
egrep
używa rozszerzonego wyrażenia regularnego, gdzie |
jest rozumiane jako logika OR. grep
domyślnie jest wyrażeniem regularnym, gdzie \|
OR
grep
podręcznika, egrep
jest przestarzałe i powinno zostać zastąpione przez grep -E
. Pozwoliłem sobie odpowiednio edytować odpowiedź.
Możesz przesłać dane wyjściowe pierwszego polecenia grep do innego polecenia grep, które pasowałoby do obu wzorców. Możesz więc zrobić coś takiego:
grep <first_pattern> <file_name> | grep <second_pattern>
lub,
cat <file_name> | grep <first_pattern> | grep <second_pattern>
Dodajmy trochę zawartości do naszego pliku:
$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt
Co zawiera plik:
$ cat test_grep.txt
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.
Teraz grep, co chcemy:
$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.
Otrzymujemy tylko linie, w których oba wzorce pasują. Możesz to rozszerzyć i przesłać dane wyjściowe do innego polecenia grep w celu uzyskania dalszych dopasowań „AND”.
grep z opcją -P
(Perl-Compatibility) i regex pozytywnego wyglądu(?=(regex))
:
grep -P '(?=.*?lemon)(?=.*?rice)' infile
lub możesz użyć poniżej:
grep -P '(?=.*?rice)(?=.*?lemon)' infile
.*?
środki dopasowania żadnych znaków .
, że zdarzenia zero lub więcej razy *
, gdy są opcjonalne, a następnie wzór ( rice
lub lemon
). ?
Czyni wszystko Opcjonalnie przed (czyli zero lub jeden raz wszystkiego dopasowane .*
)(?=pattern)
: Positive Lookahead: Pozytywna konstrukcja lookahead to para nawiasów, z nawiasem otwierającym, po którym następuje znak zapytania i znak równości.
To zwróci wszystkie wiersze z zawiera oba lemon
i rice
w losowej kolejności. Pozwoli to również uniknąć używania |
s i podwójnych grep
s.
Linki zewnętrzne:
Zaawansowane tematy Grep Pozytywne spojrzenie w przyszłość - GREP dla projektantów
Jeśli przyznamy, że udzielenie odpowiedzi, która nie jest grep
oparta, jest akceptowalne, podobnie jak powyższa odpowiedź oparta na awk
, zaproponowałbym prostą perl
linię, taką jak:
$ perl -ne 'print if /lemon/ and /rice/' my_text_file
Wyszukiwanie może ignorować wielkość liter w przypadku niektórych / wszystkich słów takich jak /lemon/i and /rice/i
. Na większości maszyn Unix / Linux perl jest instalowany, a także awk.
Oto skrypt automatyzujący rozwiązanie grep piping:
#!/bin/bash
# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}
grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n $1 ]]
then
grep -i "$1" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}
grepand "$@"
eval
go, co łatwo się