Bagaimana cara mencetak konten file hanya jika baris pertama cocok dengan pola tertentu?

11

Saya sedang menulis skrip, saya ingin memeriksa apakah baris pertama file cocok dengan pola tertentu dan jika tidak maka cetak file tersebut. Bagaimana saya bisa mencapai ini?

Bagaimana saya memeriksa polanya? Apakah ada cara untuk memeriksa pola dan berdasarkan pada output melakukan sesuatu ..

EDIT: Silakan lihat pertanyaan ini: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

Saya menginginkan sesuatu seperti ini, tetapi tidak ada yang bekerja untuk saya. Saya pada dasarnya ingin memeriksa apakah baris pertama cocok dengan pola regex atau tidak dan berdasarkan itu mencetak baris file.

Mathew
sumber
1
Apa output yang Anda harapkan? Apa pola yang Anda cari? Apa yang sudah Anda coba sejauh ini?
tachomi
@tachomi diedit, silakan lihat
Mathew

Jawaban:

17

Anda dapat melakukannya dengan ed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

Kuncinya di sini adalah mencoba mengganti PATTERNon 1stline dengan dirinya sendiri. edakan kesalahan jika tidak menemukan pola yang ditentukan sehingga ,p(cetak seluruh file) hanya akan dieksekusi jika 1s/PATTERN/&/berhasil.

Atau dengan sed:

sed -n '1{
/PATTERN/!q
}
p' infile

ini qberlaku jika baris pertama tidak ( !) cocok PATTERN, jika tidak maka akan pmerusak semua baris.
Atau, seperti yang ditunjukkan oleh Toby Speight , dengan GNU sed:

sed '1{/PATTERN/!Q}' infile

Qsama seperti qtetapi tidak mencetak ruang pola.

don_crissti
sumber
Anda bisa Qbukannya quntuk GNU sed, atau dsebelumnya q(portable) agar tidak memerlukan -nflag dan pperintah: sed '1{/PATTERN/!Q}' infileatau sed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infile, masing-masing.
Toby Speight
drestart siklus perintah Itu selalu menarik saya keluar! : - |
Toby Speight
Dengan GNU sed, sedperintah pertama mengeluh sed: -e expression #1, char 10: extra characters after command(karena p), tetapi saran eddan terakhir sedberfungsi dengan baik.
Skippy le Grand Gourou
NB: Solusi yang disediakan oleh jawaban ini memiliki kelebihan, dibandingkan jawaban lain, bahwa mereka dapat diterapkan pada pipa.
Skippy le Grand Gourou
1
@SkippyleGrandGourou - Anda mencoba mengubahnya menjadi satu-liner tanpa memisahkan perintah dengan titik koma - ini adalah cara yang tepat untuk melakukannyased -n '1{/PATTERN/!q};p'
don_crissti
15

Dengan dada alat POSIX:

{ head -n 1 | grep pattern && cat; } <file
cuonglm
sumber
1
{dobel} <manis.
mikeserv
@ mikeserv: Saya bermaksud menggunakannya untuk mencegah orang baru dari kebingungan, tetapi Stephane diedit lebih jelas.
cuonglm
8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

akan mencetak nama non-tersembunyi txtfile dalam direktori saat ini yang baris pertama cocok dengan ekspresi reguler diperpanjang patterndengan orang-orang awkinplementations bahwa dukungannextfile .

Jika alih-alih mencetak nama file, Anda ingin mencetak seluruh konten file, Anda dapat melakukan:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

Itu efisien karena hanya menjalankan satu perintah, tetapi awkbukan perintah yang paling efisien untuk membuang konten file, dengan file besar, Anda mungkin bisa mendapatkan kinerja yang lebih baik dengan melakukan sesuatu seperti:

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

Artinya, hanya digunakan awkuntuk mencetak daftar file yang cocok (dibatasi 0) dan mengandalkan catuntuk membuang konten mereka.

Stéphane Chazelas
sumber
6

Jika Anda menulis skrip shell, Anda dapat melakukannya seperti ini

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

Atau, dalam Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*
terdon
sumber
@ Stéphane Chazelas: Mungkin close ARGVlebih idiom daripada menugaskan $..
cuonglm
@terdon Milikmu terlihat seperti kode golf, semuanya dalam satu baris, tidak ada tanda kurung di sekitar nama variabel dan tidak mendorong struktur yang bersih. Dan Anda memiliki tanda dolar yang hilang ketika saya diposting, itu bukan cara untuk mengajar bash. Saya berasumsi faktor-faktor tersebut berasal dari latar perl yang juga tampaknya Anda miliki, jadi Anda akan dimaafkan! ;)
@guest hai dan selamat datang di situs! Saya mengonversi jawaban Anda menjadi komentar karena jawaban hanya boleh diposting jika mereka menjawab pertanyaan yang sebenarnya. Ini bukan forum dalam pengertian klasik dan kami hanya ingin tanya jawab murni di sini. Anda mungkin ingin melihat pusat bantuan atau mengikuti tur untuk memahami situs dengan lebih baik. Yang mengatakan, latar belakang saya sebenarnya dalam biologi jadi ya, kode saya jauh dari bersih :) Namun, saya tidak melihat bagaimana tanda kurung akan membantu di sini, tanda kutip sudah melindungi variabel. Apa yang akan mematahkan ini yang akan dilindungi dari kurung?
terdon
@guest ah, maaf, lupa Anda tidak bisa berkomentar. Merasa bebas untuk datang dan menjelaskan dalam obrolan , saya yakin saya bisa belajar sesuatu.
terdon
5

Oldschool, cukup terjemahkan kalimat Anda ke perintah standar:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

Untuk mempelajari bash, itu adalah awal yang baik. Jika Anda hanya membutuhkan solusi cepat, coba jawaban sed, awk- atau perl. Keduanya bagus, tetapi mereka adalah bahasa sendiri yang Anda perlu (dan mungkin ingin) pelajari.

Ini adalah contoh yang cukup sederhana, jadi jika Anda ingin mempelajari lebih lanjut, Anda juga dapat mencoba hal yang sama di ruby, php, js (misalnya dalam nodejs) atau bahasa lain yang memungkinkan akses file. Bahkan C / C ++ atau Java harus mudah dikelola dengan tugas kecil.

tamu
sumber
1
Ini pada dasarnya sama dengan saya kecuali bahwa Anda menggunakan if/elsebukan [ ] &&.
terdon