Hentikan ekspansi karakter wildcard shell?

91

Apakah ada cara untuk program baris perintah yang dikompilasi untuk memberi tahu bash atau csh bahwa ia tidak ingin karakter wildcard dalam parameternya diperluas?

Misalnya, seseorang mungkin menginginkan perintah shell seperti:

foo *

untuk mengembalikan nilai ASCII numerik dari karakter tersebut.

hotpaw2
sumber

Jawaban:

122

Tidak. Perluasan terjadi sebelum perintah benar-benar dijalankan.
Anda hanya dapat menonaktifkan glob sebelum menjalankan perintah atau dengan mengutip bintang.

$ # quote it
$ foo '*'

$ # or escape it
$ foo \*

$ # or disable the glob (noglob)
$ set -f
$ foo *

$ # alternative to set -f
$ set -o noglob
$ # undo it by 
$ set +o noglob
c00kiemon5ter
sumber
3
juga, jika tidak ada yang berkembang, tidak ada ekspansi. yaitu dengan kosong pwd, echo *hanya*
sam boosalis
7
@sam Ini sebenarnya bergantung pada bagaimana opsi Anda disetel. Dari tldp: "Jika tidak ada nama file yang cocok ditemukan, dan opsi shell nullglobdinonaktifkan, kata dibiarkan tidak berubah. Jika nullglobopsi ditetapkan, dan tidak ada yang cocok, kata tersebut akan dihapus."
Chris Middleton
terima kasih, saya seharusnya memenuhi syarat bahwa itu hanya dari pengamatan bukan dari pemahaman apa pun.
sam boosalis
@ c00kiemon5ter Bagaimana cara membatalkan set -f? Apakah itu unset -f?
Nam G VU
1
@NamVidset +f
Yvar Kristiansen
63

Meskipun benar bahwa sebuah perintah itu sendiri tidak dapat mematikan globbing, ada kemungkinan bagi pengguna untuk memberi tahu shell Unix agar tidak menggunakan perintah tertentu. Ini biasanya dilakukan dengan mengedit file konfigurasi shell. Dengan asumsi perintah foodapat ditemukan di sepanjang jalur perintah, berikut ini perlu ditambahkan ke file konfigurasi yang sesuai:

Untuk cangkang sh, bash, dan ksh:

alias foo='set -f;foo';foo(){ command foo "$@";set +f;}

Untuk csh dan tcsh shell:

alias foo 'set noglob;\foo \!*;unset noglob'

Untuk shell zsh:

alias foo='noglob foo'

Jalur perintah tidak harus digunakan. Katakanlah perintah foo disimpan di direktori ~ / bin, maka di atas akan menjadi:

Untuk cangkang sh, bash, dan ksh:

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

Untuk csh dan tcsh shell:

alias foo 'set noglob;$home/bin/foo \!*;unset noglob'

Untuk shell zsh:

alias foo='noglob ~/bin/foo'

Semua hal di atas telah diuji menggunakan Apple OSX 10.9.2. Catatan: Saat menyalin kode di atas, berhati-hatilah saat menghapus spasi. Mereka mungkin penting.

Memperbarui:

Geira pengguna telah menunjukkan bahwa dalam kasus shell bash

alias foo='set -f;foo';foo(){ ~/bin/foo "$@";set +f;}

bisa diganti dengan

reset_expansion(){ CMD="$1";shift;$CMD "$@";set +f;}
alias foo='set -f;reset_expansion ~/bin/foo'

yang menghilangkan kebutuhan akan fungsi foo.

Beberapa situs web yang digunakan untuk membuat dokumen ini:

David Anderson
sumber
3
Ini seharusnya menjadi jawaban yang diterima karena itu membuktikan bahwa memang mungkin untuk melakukan apa yang diinginkan OP. Untuk beberapa metode yang lebih baik dalam bash, tautan ini mendokumentasikan berbagai opsi: blog.edwards-research.com/2011/05/preventing-globbing
geira
@geira: Terkadang jawaban diterima sebelum jawaban yang lebih baik diposting. Saya yakin ini mungkin salah satu dari kasus tersebut. Saya juga percaya bahwa tanda jawaban yang paling berguna oleh pengguna akan menjadi yang pertama. Catatan: Saya menambahkan masukan Anda ke jawaban saya.
David Anderson
@geira, OP menginginkan program yang telah dikompilasi untuk berkomunikasi dengan shell; menjawab bahwa adalah mungkin untuk mengonfigurasi shell agar berperilaku seperti yang diinginkan berdasarkan perintah-demi-perintah adalah jawaban yang berguna, dan saya sendiri akan menerima yang ini, tetapi saya melihat ruang untuk tidak setuju, apakah itu sepenuhnya tepat.
Charles Duffy
Fakta bahwa itu bisa dilakukan tidak berarti itu harus dilakukan. Perubahan perilaku shell dari ekspektasi wajar pengguna untuk perintah tertentu terdengar mengejutkan dan pada akhirnya tidak diinginkan.
tripleee
@ Tripleee: Ada saat ketika orang mengharapkan relai dan tabung vakum. Yang diharapkan adalah lubang yang dilubangi pada kartu karton dan selotip kertas. Orang-orang memegang aturan geser, bukan kalkulator dan telepon. Saya kira bagi Anda ini akan diinginkan. Saya tidak terlalu peduli untuk saat-saat itu. Saya senang melihat apa yang selanjutnya.
David Anderson
8

Perluasan dilakukan oleh shell sebelum program Anda dijalankan. Program Anda tidak memiliki petunjuk apakah perluasan telah terjadi atau tidak.

   set -o noglob

akan mematikan ekspansi di shell pemanggilan, tetapi Anda harus melakukan itu sebelumnya Anda menjalankan program Anda.

Alternatifnya adalah mengutip argumen Anda, misalnya

foo "*"
Brian Agnew
sumber
4
setopt tampaknya merupakan perintah khusus zsh. Seperti yang dikatakan poster lain, untuk bash Anda gunakan set -o noglobuntuk menonaktifkan perluasan karakter pengganti.
Wirawan Purwanto
Sekarang diubah. Terima kasih
Brian Agnew
1

Hati-hati: jika tidak ada nama yang cocok dengan mask, bash meneruskan argumen sebagaimana adanya, tanpa ekspansi!

Proof (pa.py adalah skrip yang sangat sederhana, yang hanya mencetak argumennya):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']
lesnik
sumber
3
Tidak selalu. set -o nullglobatau shopt -s failglob, dan perilaku ini akan berubah (dalam dua cara yang sangat berbeda).
Charles Duffy