grep untuk garis bukan setelah pola
Saya mencoba menemukan semua baris file yang tidak mengikuti pola tertentu.
Untuk beberapa waktu saya mengalami masalah dengan history
penggunaan GNU bash
(versi 4 dan 5) di mana perintah muncul dalam duplikat. Saya berasumsi ini karena fakta bahwa saya .bashrc
memiliki baris berikut:
PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"
dan karena saya menggunakan multiplexer terminal ( screen
dan / atau tmux
) perintah yang disebutkan di atas dieksekusi beberapa kali (karena itu echo $PROMPT_COMMAND
menghasilkanhistory -a; history -n; history -a; history -n;
Dalam beberapa situasi (terutama ketika melakukan hal-hal secara bersamaan di panel / windows / frame / buffer yang berbeda) perintah terakhir yang saya masukkan disimpan dua kali atau bahkan lebih sering di my ~/.bash_history
. Ini menyebabkan entri seperti berikut:
#1596110297
yadm list -a | xargs -t ls -l
yadm list -a | xargs -t ls -l
Tak perlu dikatakan, ini cukup mengganggu. Saya baru saja (semoga) menemukan perbaikan untuk koreksi: ini TIDAK menyelesaikan masalah dengan entri duplikat di file history
-issue (dengan mengubah perintah menjadi PROMPT_COMMAND="history -a; history -n
) tetapi history
.
Sekarang saya ingin menyingkirkan entri yang digandakan.
Oleh karena itu, saat ini saya mencoba mencari ekspresi reguler untuk menandai semuanya kecuali baris yang dimulai dengan #
dan satu baris setelah itu. Ide pertama saya adalah menggabungkan grep -v
(untuk membalikkan seleksi) dan grep -A 1
(untuk mendapatkan tambahan satu baris setelah pola pencocokan). Tapi
grep -v "^#" -A 1 ~/.bash_history
tidak memberikan hasil yang saya harapkan.
Oleh karena itu pertanyaan saya: apakah ada yang punya ide bagus tentang bagaimana melakukannya dengan menggunakan grep
? Jika tidak: bagaimana saya bisa melakukannya dengan alat-alat lain ( sed
, awk
, ...)?
Jawaban
Sejauh yang saya mengerti grep -v "^#" -A 1
berarti mencetak garis yang tidak dimulai dengan tanda hash, dan satu baris setelah masing-masing. Tapi apakah Anda tidak ingin sebaliknya, mencetak baris yang tidak dimulai dengan tanda hash, dan satu baris setelah?
Diberikan file tes:
#123
echo this
echo this
#456
echo that
echo that
echo that
#789
echo third
grep -A1 ^# history.txt |grep -vxFe --
cetakan:
#123
echo this
#456
echo that
#789
echo third
Yang kedua grep
adalah menyingkirkan grep -A
cetakan pemisah kelompok .
Alternatifnya uniq history.txt
harus bekerja untuk mencetak hanya satu dari setiap rangkaian baris identik yang berurutan.
menggunakan Raku (née Perl6)
Ini sepertinya pekerjaan untuk operator "flip-flop", tersedia dalam sejumlah bahasa skrip. Di bawah ini adalah jawaban menggunakan bahasa pemrograman Raku (sebelumnya dikenal sebagai Perl6). Pertama, mulailah dengan membuat file pengujian yang lebih luas:
$ cat repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
B_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
D_yadm list -a | xargs -t ls -l
E_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
G_yadm list -a | xargs -t ls -l
H_yadm list -a | xargs -t ls -l
I_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
Sekarang untuk one-liner yang menggunakan fff
operator flip-flop Raku , yang mengimplementasikan perilaku "sed-like". Jepretan AKTIF untuk baris di mana ekspresi reguler pertama melihat (di awal baris ^^
) karakter "#" literal. Setelah AKTIF, tangkapan mengabaikan ekspresi reguler pertama dan mengevaluasi terhadap ekspresi reguler kedua, NONAKTIF ketika menemukan kecocokan dengan garis yang tidak ada (di awal baris ^^
) karakter "#". Regex 'negatif' diimplementasikan dalam kode di bawah ini menggunakan <-[#]>
, yang merupakan "Enumerated Character Class" negatif dan fitur nyata dari bahasa Raku:
$ raku -ne '.put if /^^ "#" / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
Sebenarnya, regex pertama (di sebelah kiri fff
operator infix) dapat ditulis menggunakan <+[#]>
"Enumerated Character Class" yang positif, untuk konstruksi yang lebih paralel:
$ raku -ne '.put if /^^ <+[#]> / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
Selain itu, menurut saya Anda dapat meningkatkan regex Anda dengan menuntut kecocokan untuk-atau-melawan start-of-line "#" diikuti dengan satu atau lebih digit, yaitu <digit>+
, lihat di bawah:
$ raku -ne '.put if /^^ <+[#]> <digit>+ / fff /^^ <-[#]> <-digit>+ /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
[Semua kode di atas menghapus baris duplikat yang dimulai dengan B, D, E, G, H, dan I. Satu-satunya kekhasan yang saya perhatikan adalah dua baris target berurutan seperti "# 1596110297" akan muncul di keluaran Anda, tetapi tidak jelas bagi saya jika file masukan Anda akan berisi baris berurutan seperti itu].