Bola rekursif?

80

Saya ingin menulis sesuatu seperti ini:

$ ls **.py

untuk mendapatkan semua nama file .py, berjalan secara hierarki hierarki direktori.

Bahkan jika ada file .py untuk ditemukan, shell (bash) memberikan output ini:

ls: cannot access **.py: No such file or directory

Adakah cara untuk melakukan apa yang saya inginkan?

EDIT: Saya ingin menentukan bahwa saya tidak tertarik pada kasus spesifik ls, tetapi pertanyaannya adalah tentang sintaks glob.

Paolo
sumber

Jawaban:

98

Untuk melakukan gumpalan rekursif dalam bash, Anda memerlukan globstarfitur dari bash versi 4 atau lebih tinggi.

Dari halaman bash:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Untuk pola contoh Anda:

shopt -s globstar
ls **/*.py
jordanm
sumber
2
Saya sarankan juga mengaktifkannullglob
glenn jackman
6
@glennjackman Tapi sebelum mengaktifkan nullglob, saya akan sangat menyarankan membaca peringatan berikut .
Serge Stroobandt
2
^ Peringatan telah pindah ke sini .
usandfriends
1
Dengan bash 3.2, wc -l {**,.}/*.pybekerja dengan baik
Raphael
@ Raphael Saya mengecek catatan rilis dan itu jelas mengatakan bahwa itu diperkenalkan pada 4.0. Mungkin distribusi Anda telah meng-backport tambalan untuk itu? IIRC RHEL 5 telah mendukung beberapa fitur. Juga dari catatan, sudah 9 tahun sejak bash 4 dirilis ...
jordanm
10
find . -name '*.py'

** tidak melakukan apa pun lebih dari satu *, keduanya beroperasi di direktori saat ini

selesai24
sumber
Menarik. Padahal, saya lebih fokus pada sintaks glob dengan sendirinya, karena saya harus menggunakannya dalam file konfigurasi (termasuk direktif). Saya tidak perlu daftar file.
Paolo
2
@Doug O'Neal, itu tidak lagi benar. bash sekarang telah menyalin fitur zsh (meskipun mengadopsi sintaksis lebih dekat dengan ksh93 dan seperti ksh, belum mendukung kualifikasi globing zsh namun yang membatasi kegunaannya)
Stéphane Chazelas
Ada banyak hal yang dapat Anda lakukan findjika Anda tidak memiliki bash 4. Contoh: yourcommand `find . -name '*.py'`(perhatikan backticks); find . -name '*.py' -exec yourcommand {} \;.
Mars
5

Sejak Bash 4 (juga termasuk zsh) opsi globbing baru ( globstar) telah ditambahkan yang memperlakukan pola secara **berbeda ketika diatur.

Ini cocok dengan pola wildcard dan mengembalikan nama file dan direktori yang cocok kemudian dengan mengganti pola wildcard dalam perintah dengan item yang cocok.

Biasanya ketika Anda menggunakan **, itu berfungsi mirip dengan *, tetapi itu kambuh semua direktori secara rekursif (seperti loop).

Untuk melihat apakah itu diaktifkan, periksa dengan shopt globstar(dalam skrip, gunakan shopt -q globstar).

Contoh **.pyini hanya akan berfungsi untuk direktori saat ini, karena tidak mengembalikan daftar direktori yang dapat diulang, jadi itu sebabnya Anda perlu menggunakan beberapa wildcard tingkat direktori **/*.py, sehingga bisa masuk lebih dalam.

Silakan temukan pada SO beberapa tes sintaks yang saya lakukan untuk menemukan semua file secara rekursif.

kenorb
sumber