Bagaimana cara menggunakan grep pada semua file secara non-rekursif dalam direktori?

35

Saya ingin mencari string teks di semua file dalam direktori (dan bukan subdirektori-nya; Saya tahu -ropsi melakukan itu, tetapi bukan itu yang saya inginkan).

  1. Lari

    grep "string" /path/to/dir
    

    seharusnya bisa melakukan ini, saya sudah baca, tapi itu memberi saya kesalahan:

    grep: dir: Adalah direktori

  2. Selanjutnya, saya mencoba menjalankan grepbeberapa file.

    grep "string" .bashrc .bash_aliases bekerja dengan sempurna.

    grep "string" .bash* berfungsi sebagaimana dimaksud juga.

    grep "string" * memberi saya kesalahan:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Hanya kesalahan yang dicetak, saya tidak mendapatkan garis yang cocok. Saya mencoba menggunakan -sopsi, tetapi tidak berhasil.

Jadi, pertanyaan saya:

  1. Mengapa saya tidak bisa menggunakan grepdirektori, seperti pada (1), padahal seharusnya saya bisa? Saya telah melihat hal itu dilakukan dalam banyak contoh di Internet.
    Sunting : Ketika saya mengatakan "menggunakan grep pada direktori", maksud saya "cari di semua file dalam direktori tersebut tidak termasuk subdirektori". Saya percaya bahwa inilah yang dilakukan grep ketika Anda melewatkan direktori untuk menggantikan file. Apakah saya salah?

  2. Tolong beri saya penjelasan tentang cara kerjanya grepyang akan menjelaskan perilaku perintah di (2).
    Sunting : Biarkan saya lebih spesifik. Mengapa menggunakan wildcard untuk menentukan beberapa file untuk mencari bekerja dengan .bash*dan tidak dengan *atau bahkan ./*?

  3. Bagaimana saya bisa mencari semua file dalam direktori (dan bukan subdirektori) menggunakan grep?

John Red
sumber
Anda juga mengandalkan shell yang memperluas wildcard seperti *, yang dikenal sebagai globbing. Globbing tidak termasuk nama file yang dimulai dengan titik seperti .bashrcstandar. Anda dapat mengatur opsi shell sehingga akan menyertakan file-file ini, tetapi Anda dapat membuat diri Anda sedikit berantakan jika Anda tidak tahu apa yang Anda lakukan. Panduan yang bagus untuk memahami globing dapat ditemukan di sini mywiki.wooledge.org/glob
Arronical
Saya tidak tahu mengapa, tetapi saya selalu melakukan globbing pada file tersembunyi, dan itu selalu berhasil. Saya belum mengubah pengaturan atau sesuatu. Seperti yang saya tunjukkan pada (2), ini juga berfungsi dengan baik grep "string" .bash*.
John Red
Maaf, contoh terakhir saya salah. Anda dapat mencari di file tersembunyi juga, dan menekan "adalah direktori" karena Linux secara teknis melihat direktori sebagai jenis file yang berbeda. Perintahnya adalah: grep "string" * .* 2>/dev/nullataugrep -s "string" * .*
Terrance
Juga ini stackoverflow.com/q/9217185/3701431
Sergiy Kolodyazhnyy

Jawaban:

41

Di Bash, sebuah glob tidak akan berkembang menjadi file tersembunyi, jadi jika Anda ingin mencari semua file dalam direktori, Anda perlu menentukan file yang tersembunyi .*dan yang tidak tersembunyi *.

Untuk menghindari kesalahan "Apakah direktori", Anda dapat menggunakan -d skip, tetapi pada sistem saya, saya juga mendapatkan kesalahan grep: .gvfs: Permission denied , jadi saya sarankan menggunakan -s, yang menyembunyikan semua pesan kesalahan.

Jadi perintah yang Anda cari adalah:

grep -s "string" * .*

Jika Anda mencari file di dir lain:

grep -s "string" /path/to/dir/{*,.*}

Opsi lain adalah menggunakan dotglobopsi shell, yang akan membuat glob menyertakan file-file tersembunyi.

shopt -s dotglob
grep -s "string" *

Untuk file dalam direktori lain:

grep -s "string" /path/to/dir/*

† Seseorang mengatakan bahwa saya seharusnya tidak mendapatkan kesalahan ini. Mereka mungkin benar - saya membaca tetapi tidak bisa membuat kepala atau ekor sendiri.

wjandrea
sumber
Apakah ada alasan untuk ruang antara *dan .*?
Hashim
2
@Hashim Bandingkan output echo * .*dan echo *.*jalankan di direktori home Anda, dan perbedaannya harus jelas. Kalau tidak, LMK dan saya akan menjelaskannya.
wjandrea
Menarik, echo *menampilkan file dan folder yang echo *.*tidak tersembunyi, echo .*menampilkan file yang tidak tersembunyi, menampilkan semua file, dan echo * .*menampilkan semua file dan direktori. Tapi mengapa alasan ruang antara keduanya dalam kasus terakhir? Rasanya berantakan bagi saya. Apakah tidak ada cara untuk menggabungkan keduanya untuk mendapatkan hasil yang sama? Atau sebaliknya apakah ada penjelasan sintaksis mengapa keduanya harus dipisahkan di sini, atau ada * .*kasus luar biasa?
Hashim
1
@Hashim Saya tidak yakin bagaimana Anda sampai pada kesimpulan itu, jadi izinkan saya menjelaskannya. Pertama, direktori adalah file dalam konteks ini. Dalam gumpalan, *merupakan semua file yang tidak disembunyikan (yaitu nama file yang tidak dimulai dengan titik); .*mewakili semua file yang tersembunyi (yaitu nama file yang tidak dimulai dengan titik); dan *.*mewakili semua file yang tidak disembunyikan yang mengandung titik. Dalam echo * .*, kedua gumpalan harus terpisah karena mereka gumpalan yang berbeda: satu untuk non-tersembunyi, satu untuk tersembunyi. Meskipun seperti yang saya tulis dalam jawaban saya, Anda dapat *memasukkan file tersembunyi dengan mengaktifkan dotglobopsi shell.
wjandrea
1
Penggunaan *.*umum pada Windows (DOS) sebagai cara untuk membuat daftar semua file tetapi pada * nix hanya akan menyertakan file dengan titik di dalamnya, sehingga tidak masuk akal pada * nix. Alih-alih Anda gunakan *untuk mendaftar semua file kecuali file tersembunyi, dan .*untuk daftar file tersembunyi.
thomasrutter
11

Anda perlu -d skipopsi ditambahkan.

  1. Grep mencari di dalam file. Anda dapat mencari secara rekursif, seperti yang Anda katakan, jika Anda ingin mencari file di dalam direktori.

  2. Secara default, grep akan membaca semua file, dan mendeteksi direktori. Karena secara default Anda belum menentukan apa yang harus dilakukan dengan direktori dengan -dopsi, itu memberikan output kesalahan.

  3. Mencari tepat di dalam direktori induk adalah `grep -d lewati" string "./*

anonim2
sumber
Untuk informasi lebih lanjut tentang grep, lihat man grep.
anonymous2
(a) Silakan lihat hasil edit. (B) Menggunakan -d skiptidak bekerja; pada dasarnya sama dengan -s; juga, lihat hasil edit. (c) Tidak, grep -d skip "string" ./*juga tidak berfungsi.
John Red
7

Penghitung waktu lama mungkin akan melakukan ini:

find . -type f -print0 | xargs -0 grep "string"
dathompson
sumber
3
Mengapa tidak find . -type f -exec grep string {} +?
wchargin
5
Kamu juga mau -maxdepth 1.
wchargin
@wchargin: jika Anda ingin nama file di output ketika hanya ada satu file yang saya pikir Anda inginkanfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet
1
@GregoryNisbet: Baru saja lulus -Huntuk grep.
wchargin
2

Penguraian ulang - Anda ingin mengambil file dalam satu tingkat subdirektori, tetapi tidak muncul kembali melalui semua sub-direktori?

grep forthis  *  */*

Atau jika Anda tidak ingin file di direktori saat ini

grep forthis  */*

Perhatikan ini tidak akan menemukan direktori yang dimulai dengan titik.

grep forthis  .*/*    */*   

harus melakukan pekerjaan itu.

Ada juga -maxdepthdan -mindepthbatasan parameter yang tersedia untuk findperintah juga.

Criggie
sumber
Tidak akan grep forthis */*mencari file di direktori saat ini dan satu direktori di bawah?
Hashim
@Hashim nggak kebanyakan - karena */*hanya cocok dengan satu tebasan. Jika Anda memiliki file bernama a/bdi direktori saat ini maka `* / * akan cocok dengan itu.
Criggie
0

Berikut adalah contoh untuk melewati direktori tanpa melewatkan semua kesalahan:

grep --directories='skip' 'searchString' *
Mojtaba Rezaeian
sumber