Saya memiliki direktori (mis., abc/def/efg
) Dengan banyak sub-direktori (mis .::) abc/def/efg/(1..300)
. Semua sub-direktori ini memiliki file yang sama (misalnya, file.txt
). Saya ingin mencari string hanya di ini file.txt
termasuk file lain. Bagaimana saya bisa melakukan ini?
Saya menggunakan grep -arin "pattern" *
, tetapi sangat lambat jika kita memiliki banyak subdirektori dan file.
command-line
grep
find
Rajesh Keladimath
sumber
sumber
Jawaban:
Di direktori induk, Anda bisa menggunakan
find
dan menjalankangrep
hanya file-file itu:sumber
-H
kegrep
sehingga, dalam kasus ketika hanya satu jalur dilewatkan ke sana, jalur itu masih dicetak (bukan hanya garis yang cocok dari file).Anda juga bisa menggunakan globstar.
Membangun
grep
perintah denganfind
, seperti dalam jawaban Zanna , adalah cara yang sangat kuat, fleksibel, dan portabel untuk melakukan ini (lihat juga jawaban sudodus ). Dan Muru telah diposting sebuah pendekatan yang sangat baik dari menggunakangrep
's--include
pilihan . Tetapi jika Anda hanya ingin menggunakangrep
perintah dan shell Anda, ada cara lain untuk melakukannya - Anda dapat membuat shell itu sendiri melakukan rekursi yang diperlukan :The
-H
merek Benderagrep
menunjukkan nama file bahkan jika hanya satu file yang cocok ditemukan. Anda dapat melewati-a
,-i
dan-n
bendera (dari contoh Anda) untukgrep
juga, jika itu yang Anda butuhkan. Tetapi jangan lulus-r
atau-R
saat menggunakan metode ini. Ini adalah shell yang mengulang direktori dalam memperluas pola glob yang mengandung**
, dan tidakgrep
.Instruksi ini khusus untuk Bash shell. Bash adalah shell pengguna default di Ubuntu (dan sebagian besar sistem operasi GNU / Linux) lainnya, jadi jika Anda menggunakan Ubuntu dan tidak tahu apa shell Anda, itu hampir pasti Bash. Meskipun cangkang populer biasanya mendukung
**
gumpalan direktori- traverse, mereka tidak selalu bekerja dengan cara yang sama. Untuk informasi lebih lanjut, lihat Stéphane Chazelas 's jawaban yang sangat baik untuk Hasil ls *, ls ** dan ls *** di Unix.SE .Bagaimana itu bekerja
Mengaktifkan opsi bash shell globstar membuat jalur yang cocok berisi pemisah direktori ( ). Dengan demikian, ini adalah glob yang berulang direktori. Secara khusus, seperti yang dijelaskan:
**
/
man bash
Anda harus berhati-hati dengan ini, karena Anda dapat menjalankan perintah yang mengubah atau menghapus lebih banyak file daripada yang Anda inginkan, terutama jika Anda menulis
**
ketika Anda ingin menulis*
. (Aman dalam perintah ini, yang tidak mengubah iles.)shopt -u globstar
Mematikan opsi shell globstar.Ada beberapa perbedaan praktis antara globstar dan
find
.find
jauh lebih fleksibel daripada globstar. Apa pun yang dapat Anda lakukan dengan globstar, Anda dapat melakukannya denganfind
perintah juga. Saya suka globstar, dan kadang lebih nyaman, tetapi globstar bukan alternatif umumfind
.Metode di atas tidak melihat ke dalam direktori yang namanya dimulai dengan a
.
. Terkadang Anda tidak ingin mengulang folder seperti itu, tetapi terkadang Anda melakukannya.Seperti halnya bola biasa, shell membuat daftar semua jalur yang cocok dan meneruskannya sebagai argumen untuk perintah Anda (
grep
) sebagai ganti bola itu sendiri. Jika Anda memiliki begitu banyak file yang dipanggilfile.txt
sehingga perintah yang dihasilkan akan terlalu lama untuk dieksekusi oleh sistem, maka metode di atas akan gagal. Dalam praktiknya Anda akan membutuhkan (setidaknya) ribuan file seperti itu, tetapi itu bisa terjadi.Metode yang digunakan
find
tidak tunduk pada batasan ini, karena:Cara Zanna membangun dan menjalankan
grep
perintah dengan argumen jalur yang berpotensi banyak. Tetapi jika lebih banyak file ditemukan daripada yang bisa didaftarkan dalam satu jalur, tindakan+
-minminasi-exec
menjalankan perintah dengan beberapa jalur, kemudian jalankan lagi dengan beberapa jalur lagi, dan sebagainya. Dalam halgrep
mencari string dalam banyak file, ini menghasilkan perilaku yang benar.Seperti metode globstar yang dicakup di sini, ini mencetak semua garis yang cocok, dengan jalur yang masing-masingnya berurutan.
cara sudodus berjalan
grep
secara terpisah untuk setiapfile.txt
ditemukan. Jika ada banyak file, mungkin lebih lambat dari beberapa metode lain, tetapi berhasil.Metode itu menemukan file dan mencetak jalurnya, diikuti oleh garis yang cocok jika ada. Ini adalah format output yang berbeda dari format yang dihasilkan oleh metode saya, Zanna , dan muru .
Mendapatkan warna dengan
find
Salah satu manfaat langsung dari menggunakan globstar adalah, secara default di Ubuntu,
grep
akan menghasilkan keluaran berwarna. Tapi Anda dapat dengan mudah mendapatkan ini denganfind
juga .Akun pengguna di Ubuntu dibuat dengan alias yang menjadikannya
grep
benar-benar berjalangrep --color=auto
(runalias grep
to see). Ini hal yang baik yang alias cukup banyak hanya diperluas ketika Anda mengeluarkan mereka secara interaktif , tetapi itu berarti bahwa jika Anda inginfind
untuk memohongrep
dengan--color
bendera, Anda harus menulis secara eksplisit. Sebagai contoh:sumber
bash
shell agar ini berfungsi. Anda jangan mengatakan itu secara implisit dalam "globstar shell bash pilihan" tapi dapat dengan mudah terjawab oleh orang-orang membaca terlalu cepat.**
gumpalan direktori- traverse, kritik inti Anda benar: presentasi**
dalam jawaban ini khusus untuk bash, dengan shopt menjadi bash saja dan istilah "globstar" menjadi (saya pikir) bash dan tcsh saja. Saya awalnya mengabaikan ini karena kerumitan itu, tetapi Anda benar bahwa itu agak membingungkan. Daripada membahasnya secara panjang lebar dalam jawaban ini, saya telah menautkan ke pos lain (cukup teliti) yang melakukan pekerjaan berat.-e
tidak boleh diterapkan pada jalur, tetapi ini mudah diperbaiki. Untuk perintah pertama, abaikan saja-e
. Untuk yang kedua, gunakanfind . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
ataufind . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
. Pengguna kadang-kadang lebih suka jalan Anda (dengan-e
penggunaan tetap) daripada yang lain, yang mencetak satu jalur per baris yang cocok ; Anda mencetak satu jalur per file yang ditemukan diikuti olehgrep
hasil.grep
itu sendiri tidak akan melakukan apa yang Anda lakukan. Beberapa kritik lain juga salah.grep -H
dijalankan oleh-exec
tidak akan berwarna tanpa--color
(atauGREP_COLOR
). IEEE 1003.1-2008 tidak menjamin{}
ekspansi##### {}:
, tetapi Ubuntu memiliki GNU find . Jika tidak apa-apa dengan Anda, saya akan mengedit posting Anda untuk memperbaiki-e
bug (dan mengklarifikasi kasus penggunaannya) dan Anda dapat melihat apakah Anda ingin membatalkan penghapusan. (Saya punya perwakilan untuk melihat / mengedit posting yang dihapus.)Anda tidak perlu
find
untuk ini;grep
dapat menangani ini dengan sangat baik sendiri:Dari
man grep
:sumber
find?
Metode yang diberikan dalam jawaban muru , berjalan
grep
dengan--include
bendera untuk menentukan nama file, seringkali merupakan pilihan terbaik. Namun, ini juga bisa dilakukan denganfind
.Pendekatan dalam jawaban ini digunakan
find
untuk menjalankangrep
secara terpisah untuk setiap file yang ditemukan, dan mencetak path ke setiap file tepat sekali , di atas garis yang cocok ditemukan di setiap file. (Metode yang mencetak jalur di depan setiap baris yang cocok tercakup dalam jawaban lain.)Anda dapat mengubah direktori ke atas pohon direktori tempat Anda menyimpan file-file itu. Lalu lari:
Itu mencetak path (relatif ke direktori saat ini
.
,, dan termasuk nama file itu sendiri) dari setiap file bernamafile.txt
, diikuti oleh semua baris yang cocok dalam file. Ini bekerja karena{}
merupakan tempat untuk file yang ditemukan. Setiap jalur file dipisahkan dari isinya dengan diawali dengan#####
, dan dicetak hanya sekali, sebelum baris yang cocok dari file itu. (File yang dipanggilfile.txt
yang tidak memiliki kecocokan masih memiliki jalurnya dicetak.) Anda mungkin menemukan output ini kurang berantakan daripada apa yang Anda dapatkan dari metode yang mencetak jalur di awal setiap baris yang cocok.Menggunakan
find
seperti ini hampir selalu lebih cepat daripada menjalankangrep
pada setiap file (grep -arin "pattern" *
), karenafind
mencari file dengan nama yang benar dan melompati semua file lainnya.Ubuntu menggunakan GNU find , yang selalu mengembang
{}
bahkan ketika muncul dalam string yang lebih besar , seperti##### {}:
. Jika Anda memerlukan perintah untuk bekerja denganfind
sistem yang mungkin tidak mendukung ini , atau Anda lebih suka menggunakan-exec
tindakan hanya jika benar-benar diperlukan, Anda dapat menggunakan:Untuk membuat output lebih mudah dibaca , Anda dapat menggunakan urutan pelarian ANSI untuk mendapatkan nama file berwarna. Ini membuat tajuk jalur masing-masing file lebih menonjol dari garis yang cocok yang dicetak di bawahnya:
Itu menyebabkan shell Anda mengubah kode escape untuk hijau menjadi urutan escape aktual yang menghasilkan green di terminal, dan untuk melakukan hal yang sama dengan kode escape untuk warna normal. Luput ini dilewatkan ke
find
, yang menggunakannya saat mencetak nama file. ($'
'
Kutipan diperlukan di sini karenafind
's-printf
tindakan tidak mengakui\e
untuk menafsirkan kode melarikan diri ANSI.)Jika Anda suka, Anda malah bisa menggunakan
-exec
dengan sistemprintf
perintah (yang tidak mendukung\e
). Jadi cara lain untuk melakukan hal yang sama adalah:sumber
find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
cd abc/def/efg
'direktori perubahan' :-)-e
opsiecho
? Itu akan menyebabkannya memotong-motong nama file yang mengandung garis miring terbalik. (2) Menggunakan{}
sebagai bagian dari argumen tidak dijamin berfungsi. Akan lebih baik untuk mengatakan-exec echo "#####" {} \;
atau-exec printf "##### %s:\n" {} \;
. (3) Kenapa tidak pakai saja-print
atau-printf
? (4) Pertimbangkan jugagrep -H
.find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;
2) Anda mungkin benar, tapi sejauh ini ini bekerja untuk saya. 3) -print dan -printf juga merupakan alternatif. 4) Ini sudah ada di jawaban utama. - Bagaimanapun, Anda dipersilakan dengan jawaban Anda sendiri :-)-exec
panggilan. Cukup gunakangrep -H
dan itu akan mencetak nama file (berwarna) serta teks yang cocok.Hanya untuk menunjukkan bahwa jika kondisi pertanyaan dapat diambil sastra, Anda dapat menggunakan grep langsung:
atau
sumber