Linux - „grep” od niektórych linii do końca pliku

6

Mam plik tekstowy podobny do tego:

line 1
line 2A
line 3
line 4A
line 5

Chcę „grep” z „linii 2A” do końca pliku, coś takiego

cat file.txt|some_grep "line 2A"

Chcę też „grep” z „linii 2A” do następnej linii zawierającej „A”, coś w tym rodzaju

cat file.txt| some_grep "A"

Chcę to wydrukować:

line 2A
line 3
line 4A

Które polecenie może mi w tym pomóc?

phong
źródło
Pierwszym jest dokładny przypadek, który jest trywialny dla wzorców zasięgu awk, awk '/line 2A/,0'a drugim może być awk '/line 2A/,/A/&&!/line 2A/'lub jeśli jest to co najmniej jeden znak przed Aawk '/line 2A/,/[^2]A/'
dave_thompson_085 30.01.2016
Dziękuję, jeśli mógłbyś zamienić to w odpowiedź, oznaczę to jako ... odpowiedź.
phong

Odpowiedzi:

2

(rozwinięty z komentarza)

awkma możliwość wybrania „zakresów” linii, które idealnie pasują do tej potrzeby, jak opisano w instrukcji GNU-awk (gawk) . (Ta funkcja działa w innych awksystemach, ale gawkinstrukcja jest łatwa do połączenia).

awk '/line 2A/,0'wypisuje linie zaczynające się od pierwszego pasującego line 2Ai kontynuujące do końca wprowadzania, ponieważ 0jest to warunek, który nigdy nie jest prawdziwy.

awk '/line 2A/,/A/&&!/line 2A/'rozpoczyna drukowanie od linii pasującej line 2Ai zatrzymuje się po linii pasującej, Aale NIE line 2A(a zatem nie może być tej samej linii co linia początkowa). Zacznie się od następnego line 2A i tak dalej; jeśli chcesz temu zapobiec, istnieją nieco bardziej skomplikowane sposoby.

Jeśli linie zatrzymujące zawsze mają jakiś znak inny niż 2przedtem, Amożna to uprościć, do awk '/line 2A/,/[^2]A/'którego kończy się po linii pasującej do dowolnego znaku innego niż 2, a następnie A. Możesz chcieć odmiany tego, np. Aby zatrzymać na dowolnym pojedynczym- cyfra-A różna od 2A, ale nie inna jak podobna WHAT; do tego może być warunkiem zatrzymania ,/line [013-9]A/.

dave_thompson_085
źródło
5

Chcę „grep” z „linii 2A” do końca pliku:

sed -n '/2A/,$p'
  • -n: pomija seddomyślne wyjście
  • / 2A /: linie wyjściowe z pierwszego wiersza zawierającego „2A”
  • $: do końca pliku

Chcę „grep” z „wiersza 2A” do następnego wiersza zawierającego „A”:

sed -n '/2A/,/A/p'
  • / A /: wyprowadza, aż wiersz zawiera „A”

Chcę „grep” z pierwszego wiersza zawierającego „A” do następnego:

printf "/A\n.+1,/A/p\nq" | ed -s

$ > foo echo "line 1
line 2A
line 3
line 4A
line 5"

$ sed -n '/2A/,$p' foo
line 2A
line 3
line 4A
line 5

$ sed -n '/2A/,/A/p' foo
line 2A
line 3
line 4A

$ printf "/A\n.+1,/A/p\nq" | ed -s foo
line 2A
line 3
line 4A
jlliagre
źródło
W pytaniu jest wskazówka, some_grep "A"która sugeruje, że OP chce najmniejszego zakresu linii między dwiema zawierającymi „A”. Zdefiniowanie zakresu od / 2A / do / A / jest szczególnym przypadkiem i obejściem, a nie odpowiedzią.
techraf
@techrat Odpowiadam na pytanie, które zacytowałem w mojej odpowiedzi. To prawda, że ​​istnieje sprzeczność z przekazanym parametrem. Odpowiedź zaktualizowana.
jlliagre
Niestety sed -n '/A/,/A/p'jest zła odpowiedź. Wypróbuj z plikiem wejściowym zawierającym więcej niż dwa wiersze zawierające „A”.
techraf
@techraf Rzeczywiście, odpowiedź zaktualizowana ponownie.
jlliagre
1

Myślę, że najlepszym sposobem jest użycie grepw połączeniu z cuti tail. Najpierw użyj grep, aby uzyskać linię, w której znajduje się żądany ciąg ( -ndo wypisania numeru linii; -m 1aby zatrzymać wyszukiwanie po pierwszym dopasowaniu):

grep -n -m 1 "somestring" filename.txt

To wyświetla numer linii i sam łańcuch. Aby odciąć ciąg, używamy cut ( -f1: wyjściowe pierwsze pole; -d:użyj „:” jako separatora):

grep -n -m 1 "somestring" filename.txt | cut -f1 -d:

Następnie używamy wyniku tego polecenia jako parametru w tail. Zwykle ogon drukuje ostatnie k linii, ale używając -n +k, otrzymujemy ogon do drukowania od linii k wzwyż. Łączne polecenie to:

tail -n +`grep -n -m 1 "somestring" filename.txt | cut -f1 -d:` filename.txt

Aby wypisać linie do somestringużycia headzamiast taili -n -#zamiast -n +#. Możesz także połączyć oba, aby uzyskać linie od jednego ciągu do drugiego.

agtoever
źródło
0

Wypróbuj poniższy kod -

sed -n '6,$p' infile
Elizabeth Anderson
źródło
3
Czy potrafisz zmienić to w „naukę”, poszerzając swoją odpowiedź, aby wyjaśnić polecenie? Dzięki.
fixer1234 30.01.16
1
Ignoruje to warunki określone przez OP na początku i (nawet po modyfikacji) nie rozwiązuje drugiego problemu: od „linii 2A” do następnej linii zawierającej „A” .
techraf
0

Metoda sed jest właściwą drogą, ale co zrobić, jeśli chcesz zachować górne linie, ale ich nie grepować?

Oto sposób:

{ head -1 file.txt ; sed 1d file.txt | grep <whatever> ;}

Co tu się dzieje?

Najpierw wypluwamy górną linię (head -1 plik.txt) Następnie usuwamy górną linię (sed 1d plik.txt) i grep właśnie to.

Całość jest otoczona przez {..;}, więc możesz później potokować lub przekierowywać zarówno nagłówek, jak i grepowane ciało. Lubię to:

{head -1 plik.txt; sed 1d plik.txt | grep;}> newfile.txt

Jeśli chcesz pominąć pierwsze 10 linii, zmień to na to

{head -10 plik.txt; sed 1,10d plik.txt | grep;}

Ken Beer
źródło