Mengapa $ anchor end-of-line tidak bekerja dengan perintah grep, meskipun anchor front-of-line ^ adalah?

19

Sangat baru untuk UNIX tetapi tidak baru untuk pemrograman. Menggunakan Terminal di MacBook. Untuk keperluan mengelola dan mencari daftar kata untuk konstruksi teka-teki silang, saya mencoba untuk membiasakan diri dengan perintah Grep dan variasinya. Tampaknya cukup mudah tetapi menutup telepon dengan apa yang saya pikir seharusnya menjadi kasus sederhana.

Ketika saya masuk

grep "^COW" masternospaces.txt

Saya mendapatkan apa yang saya inginkan: daftar semua kata yang dimulai dengan SAP.

Tapi saat aku masuk

grep "COW$" masternospaces.txt

Saya berharap untuk mendapatkan daftar kata yang diakhiri dengan SAP (ada banyak kata seperti itu), dan tidak ada yang dikembalikan sama sekali.

File tersebut adalah file teks biasa, dengan setiap baris hanya sebuah kata (atau frase kata tanpa spasi) di semua huruf besar.

Adakah yang bisa terjadi di sini?

DTalvacchio
sumber
3
Apa asal usul file masternospaces.txt? mungkinkah ini memiliki terminasi garis gaya Windows (CR-LF) dan bukan LF gaya Unix?
steeldriver
2
Tidak yakin, tetapi apakah Anda mencari daftar kata atau daftar baris ... ?
mikeserv
steeldriver-- Sesuatu seperti itu adalah pikiran pertamaku. Tidak yakin bagaimana memeriksa apa yang terjadi di sana, atau bahkan apa kemungkinannya. Diasumsikan bahwa pengembalian akhir adalah pengembalian akhir. File itu adalah ringkasan besar dari beberapa sumber. Saya bahkan tidak yakin mana yang akan dianggap sebagai file asli. Dan sudah melalui setidaknya tiga pengolah kata pada PC dan mesin Mac. Apa yang mungkin menjadi cara terbaik untuk melihat pemutusan apa yang digunakannya?
DTalvacchio
mikeserv - Dalam file .txt ini, setiap baris hanyalah sebuah kata (atau frasa tanpa spasi di antara kata-kata, jadi sekali lagi "kata"). Jadi saya mencari garis, saya kira. . . Hanya saja setiap baris hanya memiliki satu kata yang saya pertimbangkan untuk keperluan teka-teki silang.
DTalvacchio
1
Anda dapat menggunakan hexdumpuntuk memeriksa dengan tepat bagaimana akhir baris Anda diformat. Saya sarankan Anda menggunakan format favorit saya: hexdump -e '"%08_ad (0x%08_ax) "8/1 "%02x "" "8/1 "%02x "' -e '" "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt. Dengan output, periksa ujung garis: 0a-> LF,0d -> CR.
user43791

Jawaban:

23

Seperti yang disebutkan @steeldriver, masalah ini kemungkinan disebabkan oleh gaya garis akhir yang berbeda dari yang grepdiharapkan.

Untuk memeriksa ujung garis

Anda dapat menggunakan hexdumpuntuk memeriksa dengan tepat bagaimana akhir baris Anda diformat. Saya sarankan Anda menggunakan format favorit saya:

hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt

Dengan output, periksa ujung garis: 0a-> LF, 0d-> CR. Contoh yang sangat cepat akan memberikan sesuatu seperti ini:

$ hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt
00000000 (0x00000000)    4e 6f 20 43 4f 57 20 65   6e 64 69 6e 67 0d 0a 45    No COW e|nding..E
00000016 (0x00000010)    6e 64 69 6e 67 20 69 6e   20 43 4f 57 0d 0a          nding in| COW..

Catatan akhir baris dalam format dos: 0d 0a.

Untuk mengubah akhir baris

Anda bisa lihat sini atau di sini untuk berbagai metode mengubah akhir baris menggunakan berbagai alat, tetapi untuk satu kali, Anda selalu dapat menggunakan vi / vim:

vim masternospaces.txt
:set fileformat=unix
:wq

Untuk grep tanpa mengubah apa pun

Jika Anda hanya ingin grep mencocokkan apa pun akhir baris, Anda selalu bisa menentukan akhir baris seperti ini:

grep 'COW[[:cntrl:]]*$' masternospaces.txt

Jika baris kosong ditampilkan, Anda dapat memeriksa bahwa Anda memang cocok dengan sesuatu menggunakan -v opsi cat:

grep 'COW[[:cntrl:]]*$' masternospaces.txt | cat -v

Favorit pribadi saya

Anda juga bisa grep dan standarisasi output menggunakan sed :

sed -n '/COW^M*$/{;s/^M//g;p;};' masternospaces.txt

dimana ^M diperoleh dengan mengetik Ctrl-V Ctrl-Mdi keyboard Anda.

Semoga ini membantu!

pengguna43791
sumber
Itu semua sangat membantu. Saya kehabisan waktu hari ini tetapi akan melihat semua ini erat besok dan melihat apa. Jika sementara itu ada di antara Anda yang memiliki tautan ke panduan referensi perintah Unix favorit Anda sehingga saya bisa belajar sedikit tentang bagaimana segala sesuatunya bekerja, saya akan menghargainya. Saya sudah mengambil bagian di sana-sini tetapi belum menemukan satu sumber yang masuk ke penjelasan saya. Terima kasih semuanya dan akan memeriksa besok dengan pembaruan yang diharapkan berhasil. --D
DTalvacchio
Sayang sekali posting ini tidak memiliki penutupan, setidaknya bagi saya. Saya tidak bisa, untuk kehidupan saya, mencari cara untuk mencocokkan akhir baris. Jika saya melakukan hex dump, saya tidak dapat menemukan akhiran yang bagus seperti contoh Anda di atas. Saya tidak terbiasa dengan hex sehingga saya mungkin tidak membacanya dengan benar. Saya juga mencoba yang [[:cntrl:]]disarankan @ user43791 dan masih tidak cocok dengan apa pun untuk saya. Ini tidak masuk akal. Saya menggunakan GNU grep 2.20 dan mem-parsing output dari nDPI yang ditulis ke file teks
harperville
@harperville Jika Anda cat -v yourfile.ext, apa yang Anda lihat?
user43791
Yah, tidak ada yang menarik atau tidak terduga. Hanya isinya seperti yang saya harapkan untuk melihatnya. Adakah yang spesifik yang Anda cari? Saya tidak bisa menempelkan hasilnya di sini tetapi saya hanya melihat isinya. Biasa "Teks ASCII bahasa Inggris" menurut file.
harperville
@harperville Tidak ada tambahan "^ M" di akhir setiap baris? Bisakah Anda menempelkan beberapa baris pertama hex?
user43791
1

Meskipun Anda dapat menggunakan sintaks RegEx 'standar' dengan grep (seperti pada jawaban @ user43791 ), grep juga memiliki pengidentifikasi lain untuk menandai batas input.

Pencocokan untuk awal dan akhir seluruh baris adalah \`(backtick) (bukan ^) dan \'(apostrof) (bukan $).

Jadi untuk perintah asli Anda, Anda akan menggunakan: grep "COW\'" masternospaces.txt

Catatan: Penting juga untuk dicatat bahwa ?dan +akan diperlakukan secara literal kecuali Anda menghindarinya menggunakan \?dan \+menjadikannya sebagai mitra pemilih gaya RegEx.

Sumber: grepsintaks ekspresi reguler

samthecodingman
sumber
grep mengambil ^ (tanda sisipan) untuk memulai dan \ '(tanda kutip) untuk akhir
GypsyCosmonaut
1

Cara lain untuk menghapus \rsebelum grep:

... | dos2unix | egrep 'COW$' | ...

Saya suka itu sangat jelas karena saya tidak ingat hal-hal seperti [[:cntrl:]]lama.

Javier
sumber
-2

"COW $" ketika bash mengatur pararameter untuk grep, itu ditafsirkan sebagai 'COW' di mana memperlakukan "$" sebagai "", karena $ adalah simbol pelarian. ketika tidak ada yang dihasilkan oleh $, itu ditafsirkan sebagai string kosong oleh bash shell jadi, Anda harus menggunakan grep 'COW $' masternospaces.txt sebagai gantinya.

yangyang
sumber
3
karena tidak ada ekspansi yang valid $, itu akan dibiarkan oleh bash dan digunakan oleh grep. Lihat sendiri: echo "COW$"- $masih akan ada di sana.
Jeff Schaller
-3

Di BSD grep Anda harus keluar dari "$" dan lampirkan string Anda dalam tanda kutip ganda:

"COW\$"
pengguna297403
sumber
1
Um ... tidak. Tidak $akan khusus untuk shell, karena barang-barang setelah itu bukan nama variabel shell yang valid. Menggunakan tanda kutip tunggal di sekitar string statis adalah ide yang lebih baik, tetapi tidak akan membuat perbedaan di sini.
Kusalananda