buat output grep tanpa tertinggal baris baru

8

Harap pertimbangkan cuplikan ini:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')

Saya ingin memasukkan kata terakhir dalam variabel jika beberapa kondisi pola cocok dengan baris dalam file teks sewenang-wenang

Masalah saya adalah bahwa variabel Xmemiliki CR atau LF atau CRLF pada akhirnya, tergantung pada file sumber, yang ingin saya singkirkan, karena mengganggu operasi selanjutnya yang ingin saya lakukan.
Saya bahkan mencoba sesuatu seperti:

X=$(grep -m1 'some-pattern' some-file | sed -n 's/.* \([A-Za-z]\+\)/\1/p')

dengan demikian mengharapkan sedoutput dibatasi [A-Za-z]+tetapi masih ada byte gangguan ini di dalam variabel X.

Bagaimana saya bisa menyingkirkan itu, tanpa menggunakan terlalu banyak kode seperti lihat apa yang byte yang di akhir dengan xxdkemudian cutitu dan serupa komplikasi?

zetah
sumber

Jawaban:

4

Sepertinya awkakan menjadi pilihan yang lebih baik untuk kebutuhan Anda, karena masalah ini tidak ada karena fakta bahwa ia dapat menggunakan bidang dan catatan:

x=$(awk '/some-pattern/ { sub(/\r$/, "") ; printf("%s", $NF) ; exit }' some-file)

Substitusi tersebut menghindari masalah Anda dengan ujung jalur CRLF.

sub(/\r$/, "")menghapus trailing CR, jika ada. Sebagai awkmemperlakukan \nsebagai pemisah catatan (baris), Anda tidak perlu menghapusnya, karena tidak ada dalam data yang sedang dilihat.

printf("%s", $NF)mencetak bidang terakhir ( $NF) tanpa baris baru ( printdan beberapa awkfungsi lainnya menambahkan baris baru secara default).

exitterjadi setelah dua tindakan pertama - ini sama dengan m1di grepbaris perintah Anda . Ini memastikan bahwa awkkeluar setelah pelaksanaan dua perintah sebelumnya - dan karena perintah ini dikeluarkan pada pertandingan, dan awk mengevaluasi data dengan cara FIFO, ini hanya akan mencetak pertandingan pertama.

Chris Down
sumber
Terima kasih, terlihat elegan tapi sayangnya CRLF masih di dalamX
zetah
:) Sekarang tidak lagi terlihat elegan dan masih tidak bagus
zetah
@zetah - Tidak akan ada CR, tetapi akan ada LF. Saya kesulitan memahami apa yang Anda inginkan dari pertanyaan, semoga hasil edit saya melakukan apa yang Anda inginkan.
Chris Down
OK, kali ini ia melakukannya dengan baik - menampilkan kata terakhir dalam satu baris jika garis tersebut memenuhi beberapa persyaratan pola - tidak tahu, mungkin itu jelas bagi saya karena saya memiliki masalah ini, dan kemudian sulit untuk dijelaskan sebagai penutur bahasa Inggris yang bukan penutur asli . Bagaimanapun, saya akan menunggu lebih banyak jika seseorang mengatasinya dengan grep/sedsolusi awk(yang saya tidak mengerti), dan jika tidak saya akan menggunakannya. Terima kasih
zetah
@zetah - Saya akan menambahkan penjelasan sehingga Anda dapat memahaminya dengan lebih baik, satu detik.
Chris Down
7

The ``atau $()akan menghapus baris dari akhir, tetapi untuk melakukan hal ini secara programatik, penggunaan tr.

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\012\015'

Ini akan menghapus carriage return dan / atau baris baru dari string.

Apa yang mungkin menjadi masalah adalah bagaimana Anda kemudian menampilkan hasilnya. Misalnya, secara default, echomenambahkan baris baru. Anda mungkin ingin menggunakan echo -natau printf.

Arcege
sumber
Ini juga akan menghapus carriage return yang mungkin terjadi di seluruh string, yang mungkin tidak diinginkan.
Chris Down
Ya, walaupun mungkin untuk memiliki carriage return yang tertanam dalam satu baris, itu sangat jarang. The -m1akan memastikan bahwa hanya ada satu output line, yang kemungkinan besar, akan memiliki carriage return di akhir.
Arcege
ah tr... menarik, berfungsi baik pada file LF dan CRLF. Saya akan berpikir \010\013untuk beberapa alasan, dan juga \f\rberfungsi dengan benar. Tentang hasilnya: Saya tidak benar-benar menempatkan output dalam variabel tetapi sebagai variabel terlampir $()dalam pola untuk greppertandingan - some pipe | grep -o " $(...) ". Terima kasih atas komentar
zetah
3

Saya lebih suka cara ini

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d '\n'
Steven Penny
sumber
2

Ini bekerja untuk saya:

grep -m1 'some-pattern' some-file | sed -n 's/.* //p' | tr -d "\n" | tr -d "\r"
Funky_Pandy
sumber
0

Mengapa tidak dibiarkan sedsaja [\r\f]:

# using Bash's $'string' idiom (that decodes ANSI C escape sequences)
# cf. http://wiki.bash-hackers.org/syntax/quoting#ansi_c_like_strings
- X="$(grep -m1 'some-pattern' some-file | sed -n 's/.* //p')"
+ X="$(grep -m1 'some-pattern' some-file | sed -n -e $'s/[\r\f]*$//' -e 's/.* //p')"

Pendekatan kedua Anda tidak memiliki regex akhir untuk menangkap trailing CR \r,.

# sample code to remove trailing \r with sed
# cf. http://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)/\1/p' | od -c
printf 'a b c\r' | sed -n 's/^.* \([[:alpha:]]\{1,\}\)[[:space:]]*/\1/p' | od -c

# keeps trailing space after c
printf 'a b c \r' | sed -n 's/^.* \([[:alpha:] ]\{1,\}\)[[:space:]]*/\1/p' | od -b
chad
sumber
0

Versi normal grep (termasuk grep -P) selalu menampilkan umpan baris dengan pasangannya, jadi jika Anda hanya memiliki satu hasil (atau Anda hanya ingin agar umpan baris akhir yang ditambahkan dihapus), cukup dengan menghapus karakter akhir saja dari output, yang dapat Anda lakukan dengan menyalurkannya head -c-1.

Jon
sumber