Bagaimana saya bisa mencegah ekspansi Bash dari meneruskan file yang dimulai dengan "-" sebagai argumen?


14

Saya mencoba mencari string secara rekursif greptetapi saya mendapatkan ini:

$ grep -r "stuff" *
grep: unrecognized option '---corporate-discount.csv'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

Bagaimana saya bisa mencegah Bash agar tidak meneruskan file yang dimulai dengan -sebagai argumen?



3
Anda tidak benar-benar ingin mencegah shell dari mengirimkan file-file ini, bukan? Pertanyaannya adalah bagaimana mengatakan grepbahwa itu bukan pilihan.
DonHolgo

11
... agar jelas, bash tidak mengontrol hasil mana yang diperlakukan sebagai opsi vs diperlakukan sebagai argumen; itu dalam kendali program penerima. Anda akan mendapatkan perilaku yang sama dengan, katakanlah, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv'])dengan Python, tidak ada bash di mana pun.
Charles Duffy

1
Bacaan terkait: Unix Wildcards Gone Wild , tentang masalah keamanan yang dapat disebabkan oleh penggunaan *perintah. SEMUA ini bisa dihindari dengan menggunakan ./*sebagai gantinya.
Wildcard

1
@Wildcard, menggunakan --sigil sebagai opsi akhir juga sangat masuk akal; Pedoman sintaks utilitas POSIX mengharuskannya dihormati; lihat pedoman # 10. (Tentu, tidak semua program mengikuti pedoman POSIX, tetapi jawabannya adalah untuk merangkai penulis program yang menyinggung dan / atau mengeluarkan mereka dari industri).
Charles Duffy

Jawaban:


43

Pertama, perhatikan bahwa interpretasi argumen yang dimulai dengan tanda hubung tergantung pada program yang sedang dijalankan, grepatau lainnya. Shell tidak memiliki cara langsung untuk mengendalikannya.

Dengan asumsi Anda ingin memproses file seperti itu (dan tidak mengabaikannya sama sekali) grep, bersama dengan sebagian besar program, dikenali --sebagai indikasi akhir dari opsi, jadi

grep -r -e "stuff" -- *

akan melakukan apa yang Anda inginkan. Apakah -eada dalam kasus stuffdimulai dengan -juga.

Atau, Anda juga dapat menggunakan:

grep -r -e "stuff"  ./*

Yang terakhir itu juga akan menghindari masalah jika ada file yang dipanggil -di direktori saat ini. Bahkan setelah --pemisah, grepdiartikan -sebagai makna stdin, sementara itu ./-adalah file yang disebut -dalam direktori saat ini.


8

Untuk mencegah ekspansi Bash dari meneruskan file yang dimulai dengan "-" Anda dapat menggunakan:

echo [!-]*

Yang bekerja dengan baik di sebagian besar shell, atau, khusus untuk ksh, bash, zsh:

echo !(-*)

Misalnya: dalam direktori dengan file ini

$ echo *
a b c ---corporate-discount.csv d -e --option.txt

Hanya akan daftar (asalkan extglobaktif):

$ shopt -s extglob
$ echo !(-*)
a b c d

$ echo [!-]*
a b c d

Tetapi jika yang Anda inginkan adalah memroses semua file sambil memberi tahu grep untuk menghindari menafsirkan file yang dinyatakan dengan -opsi sebagai, maka tambahkan saja ./:

grep -r "stuff" ./*

Atau, jika ada jaminan bahwa tidak ada file yang dipanggil persis -ada dalam file yang terdaftar (grep akan mengartikan kesepian -sebagai dibaca dari stdin ), Anda dapat menggunakan:

grep -r -- "stuff" *

Ya, karena pertanyaannya adalah tentang bash, shell GNU, tampaknya masuk akal untuk mengasumsikan bahwa grep GNU tersedia, dapat diinstal, atau sebenarnya sedang digunakan. @ StéphaneChazelas
Isaac

Ya, a grep -r -- stuff *lebih sederhana, dan bekerja dengan greps non-GNUish juga. Jadi: tambah, terima kasih. @ StéphaneChazelas
Isaac

@Isaac Saya tidak akan mengatakan itu asumsi yang masuk akal "jika bash tersedia, GNU grep juga tersedia". Ambil contoh FreeBSD: bash tidak diinstal secara default , yang dapat diinstal kemudian, tetapi tidak ada efek pada grep - itu tetap versi BSD dari grep kecuali GNU grep diinstal secara eksplisit. Tapi itu nitpick kecil. Saya suka pendekatan alternatif via extglob, maka +1 memberi jawabannya
Sergiy Kolodyazhnyy

2
@SergiyKolodyazhnyy, AFAIK, greppada FreeBSD masih berbasis pada GNU grepdan masih memiliki kesalahan di mana opsi dikenali setelah tidak ada opsi. Bahkan BSD seperti OpenBSD yang telah menulis ulang grepmembuat mereka GNU kompatibel untuk portabilitas terbalik (dan masih menunjukkan perilaku itu di sini). Pada macOS, sh adalah bash, tapi saya berharap grep mereka tidak menunjukkan perilaku seperti macOS yang dimaksudkan untuk menjadi POSIX bahkan tanpa $ POSIXLY_CORRECT. Dalam kasus apapun, grep OP adalah GNU-kompatibel karena memberikan kesalahan itu.
Stéphane Chazelas

1
Lihat juga echo [!-]*sebagai standar yang setara dengan ksh (atau bash -O extglob's) echo !(-*).
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.