ekspansi shell (A | B) dalam nama file?

9

Apakah mungkin untuk memperluas orpilihan di shell ketika membaca file misalnya.

Yang saya maksudkan adalah bahwa, misalnya, grepmendukung sintaksis seperti (A|B)mencocokkan A atau B dalam sebuah file.

Demikian pula, jika saya memiliki file-file ini:

file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

Aku bisa melakukan cat file{1..5}.txtdi bash, karena memperluas jangkauan. Apakah ada cara yang setara untuk melakukan ini hanya untuk beberapa file?

Misalnya cat file(1|5).txtdan hanya mencetak 2 itu?

Joe Healey
sumber

Jawaban:

16

Pola globbing nama file standar yang cocok dengan digit adalah [0-9]. Ini cocok dengan satu digit:

cat file[0-9].txt

Untuk memilih hanya dua di antaranya:

cat file[25].txt

Untuk angka yang lebih besar dari 9, ekspansi brace akan berguna (tetapi lihat catatan di bawah untuk perbedaan antara pola globbing dan ekspansi brace):

cat file{25..60}.txt

Sekali lagi, ekspansi brace memungkinkan untuk nomor individual juga:

cat file{12,45,900,xyz}.txt

(perhatikan bahwa dalam contoh di atas, ekspansi brace tidak melibatkan loop aritmatika, tetapi hanya menghasilkan nama berdasarkan string yang disediakan).

Di bash, dengan extglobopsi shell diaktifkan ( shopt -s extglob), yang berikut ini juga akan berfungsi:

cat file@(12|45|490|foo).txt

The @(...)Pola akan cocok salah satu dari termasuk |pola -delimited.


Perbedaan antara pola globbing sebagai [...]dan @(...)dan ekspansi brace, adalah bahwa ekspansi brace dihasilkan pada baris perintah dan mungkin tidak benar-benar cocok dengan nama yang ada di direktori saat ini. Pola globbing nama file akan cocok dengan nama, tetapi shell tidak akan mengeluh jika tidak semua nama ada. Jika tidak ada nama yang cocok, polanya akan tetap tidak berkembang, kecuali jika nullglobopsi shell diatur, dalam hal ini polanya dihilangkan.

Contoh:

touch file1

ls file[0-9]

Di sini, hanya daftar file yang file1akan ditampilkan.

Dengan ls file{0..9}, lsakan mengeluh tentang tidak menemukan file0, file2dll.

Dalam contoh berikut, perintah pertama hanya akan menyentuh nama yang sudah ada yang cocok dengan pola yang diberikan, sedangkan baris kedua akan membuat file yang belum ada:

touch file[0-9]

touch file{0..9}
Kusalananda
sumber
@ thecarpy Maaf, tapi itu bukan pola yang cocok misalnya file45.txt. Ekspresi braket [...]bekerja seperti dalam ekspresi reguler tetapi digunakan !sebagai ganti ^untuk mengatakan "tidak dalam". Sebuah [...]pola akan selalu cocok dengan satu karakter.
Kusalananda
Kamu benar! BTW, saya {1,2}juga tidak mematuhi POSIX ... mempelajari beberapa hal baru hari ini!
thecarpy
2
Fakta bahwa ekspansi brace tidak perlu cocok dengan file nyata bisa sangat berguna, jika Anda menggunakannya untuk (misalnya) menghasilkan pola untuk diteruskan grep, menghasilkan URL untuk diteruskan curl, dan sebagainya ... tetapi juga bisa membingungkan kepada orang-orang yang terbiasa bekerja dengan gumpalan.
Kevin
@Kevin Benar. Perluasan brace tidak harus tentang nama file.
Kusalananda
7

Sintaks yang digunakan adalah file{1,2}yang akan mengevaluasi ke file1dan file2.

$ ls
$ touch file{1,2,3,4,5,6,7,8,9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Seperti yang ditunjukkan oleh Inian di bawah ini ... akan lebih mudah dilakukan touch file{1..9}dalam contoh kasus ini ...

$ ls
$ touch file{1..9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

Anda juga dapat menggunakan banyak ekspresi, seperti:

$ ls
$ touch file{1..9}{a..z}
$ ls
file1a file1b file1c
[...]
file9x file9y file9z

Ya, di atas akan membuat 234 ( 9kali 26) file.

sampah
sumber
1
Ini file{1,2} sintaks ini juga mudah untuk file rename:mv some_very_long_filename.txt{,.bak}
Eric Duminil
6

Ya, Anda dapat menggunakan ekspansi brace di bashshell. Untuk hanya beberapa file lakukan file{1..2}saja atau samafile{1,2}

Atau jika Anda khawatir tentang file yang tidak ada dalam beberapa kasus, lakukan saja perulangan sederhana,

for file in file{1..4}.txt; do
    [ -f "$file" ] || continue
    echo "$file" # Do other actions on file here
done

Atau jika hanya menggabungkan adalah satu-satunya operasi Anda pada file dan jika Anda tidak yakin file mana yang tidak dapat hadir pada suatu titik waktu, hanya catmereka dan menekan kesalahan. Mengarahkan ulang kesalahan standar ke /dev/nullakan menekan kesalahan jika file tidak tersedia.

cat file{1,5}.txt 2>/dev/null

atau gunakan ekspresi glob file[15]yang tidak mengeluh tentang kesalahan jika file tidak ditemukan.

cat file[15].txt
Inian
sumber
2
Tidak, tidak ada kekhawatiran tentang file yang tidak ada di sana, saya hanya ingin menunjukkan isi dari 2 file yang diberi nomor secara numerik, tetapi itu tidak berurutan, jadi file{1,5}sintaks koma adalah semua yang saya lewatkan!
Joe Healey