Bagaimana saya bisa mendapatkan direktori berdasarkan isi dari dua baris berturut-turut?

11

Bagaimana saya bisa mendapatkan direktori untuk baris yang berisi "Foo", tetapi hanya mendapatkan kecocokan ketika baris berikutnya juga berisi "Bar"?

Nathan Long
sumber
Masalahnya sekarang sama sekali berbeda dari aslinya: / Mungkin lebih baik mengembalikan versi lama & POST yang lain? Apalagi pertanyaan baru itu tidak jelas bagi saya.
Gilles Quenot
@sputnick - bagaimana bisa begitu? Saya menentukan direktori ketika saya pertama kali memposting pertanyaan; Saya hanya berani karena orang tidak memperhatikan.
Nathan Long
Bagaimanapun, itu akan berhasil, saya akan mengedit POST saya sesuai.
Gilles Quenot

Jawaban:

7

@ warl0ck menunjuk saya ke arah yang benar dengan pcregrep, tetapi saya berkata "berisi", bukan "adalah", dan saya bertanya tentang direktori, bukan file.

Ini sepertinya bekerja untuk saya.

pcregrep -rMi 'Foo(.*)\n(.*)Bar' .
Nathan Long
sumber
6

Grep sendiri sepertinya tidak mendukungnya, gunakan pcregrep sebagai gantinya:

Foo
Bar
Foo
abc

pcregrep -M "Foo\nBar" file

Punya:

Foo
Bar
bunga aster
sumber
3
OP tidak mengatakan itu Foodan Barakan terdiri dari seluruh lini.
tojrobinson
6

Dengan sedskrip:

#!/bin/sed -nf

/^Foo/{
    h         # put the matching line in the hold buffer
    n         # going to nextline
    /^Bar/{   # matching pattern in newline
        H     # add the line to the hold buffer
        x     # return the entire paragraph into the pattern space
        p     # print the pattern space
        q     # quit the script now
    }
}

Untuk menggunakannya:

chmod +x script.sed
printf '%s\n' * | ./script.sed

Di printfsini menampilkan semua file dalam direktori saat ini pada setiap baris, dan meneruskannya ke sed.

Catatan : ini disortir berdasarkan urutan abjad.

Info lebih berguna pattern spacedan hold space DI SINI .

grymoire.com memiliki hal-hal yang sangat baik tentang shellpemrograman.

Gilles Quenot
sumber
Apa h, n, H, x, p, qartinya? Sangat menarik.
Yamaneko
Lihat komentar saya. Info lebih lanjut tentang pattern space& hold space: grymoire.com/Unix/Sed.html#uh-56 atau dalam bahasa Perancis commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Gilles Quenot
POST diadaptasi untuk bekerja pada direktori
Gilles Quenot
4

Hanya menggunakan grep, Anda bisa membuat pipa berikut:

grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'

Yang pertama grepakan mendapatkan semua baris yang berisi Fooserta baris setelah pertandingan. Lalu kami mendapatkan garis yang berisi Barserta garis sebelum pertandingan, dan akhirnya mengekstrak garis dari output yang berisi ini Foo.

EDIT: Seperti yang ditunjukkan oleh manatwork , ada beberapa kasus bermasalah yang harus diperhatikan. Meskipun tantangan yang menarik, karena grepfungsionalitas yang berorientasi pada garis, solusi apa pun yang ada kemungkinan adalah 'retas' dan Anda mungkin lebih baik menggunakan sesuatu seperti pcregrepyang lebih cocok untuk tugas yang sedang dihadapi.

tojrobinson
sumber
Bagus. Saya bertanya tentang direktori; ini sepertinya berhasil:find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Nathan Long
Itu juga akan mencantumkan kejadian dengan "Foo" dan "Bar" pada baris yang sama.
manatwork
@manatwork: Baris yang berisi "Foo" dan "Bar" adalah "baris yang berisi 'Foo'" yang merupakan apa yang ditanyakan.
tojrobinson
1
@tojrobinson, bagaimana dengan "tetapi hanya mendapatkan kecocokan ketika baris berikutnya juga mengandung bagian" Bar ""? pastebin.com/Yj8aeCEA
manatwork
3

Sementara saya lebih suka menggunakan solusi Nathan pcregrep, berikut adalah solusi hanya menggunakan grep

grep -o -z -P  'Foo(.*)\n(.*)Bar' file

Penjelasan opsi:

  • -ohanya mencetak bagian yang cocok. Diperlukan sejak dimasukkannya -zakan mencetak seluruh file (kecuali ada \ 0 di suatu tempat)
  • -z Perlakukan input sebagai satu set garis, masing-masing diakhiri dengan byte nol (karakter ASCII NUL) alih-alih baris baru.
  • -P sintaks perl regex

EDIT: Versi ini mencetak seluruh baris yang cocok

    grep -o -P -z  '(.*)Foo(.*)\n(.*)Bar(.*)' file
bbaja42
sumber
1
Trik keren apa -z. Beberapa "(. *)" Sebelum dan sesudah seluruh ekspresi akan membuatnya menampilkan seluruh baris yang cocok. Untuk saat ini substring sebelum "Foo" dan setelah "Bar" tidak ditampilkan.
manatwork
1

Dengan awk:

awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
     /foo/ {prev=$0; next}
     {prev=""}' file1...

(catatan umum tentang batasan awk: berhati-hatilah bahwa jika beberapa nama file mungkin berisi "=" karakter, Anda harus meneruskannya sebagai ./filenameganti filenameawk)

Stéphane Chazelas
sumber