Czy zatrzymać rozwijanie znaków wieloznacznych powłoki?

88

Czy istnieje sposób, aby skompilowany program wiersza poleceń powiedział bashowi lub csh, że nie chce, aby w swoich parametrach były rozwijane żadne symbole wieloznaczne?

Na przykład, ktoś może potrzebować polecenia powłoki, takiego jak:

foo *

aby po prostu zwrócić numeryczną wartość ASCII tego znaku.

hotpaw2
źródło

Odpowiedzi:

119

Nie. Rozwinięcie następuje przed faktycznym wykonaniem polecenia.
Glob można wyłączyć tylko przed uruchomieniem polecenia lub przez zacytowanie gwiazdki.

$ # 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
źródło
3
jeśli nie ma nic do rozbudowy, nie ma ekspansji. tzn. z pustym pwd, echo *jest po prostu*
sam boosalis
7
@sam To właściwie zależy od tego, jak ustawione są twoje opcje. Z tldp: „Jeśli nie zostaną znalezione żadne pasujące nazwy plików, a opcja powłoki nullglobjest wyłączona, słowo pozostaje niezmienione. Jeśli nullglobopcja jest ustawiona i nie zostaną znalezione żadne dopasowania, słowo jest usuwane”.
Chris Middleton
dzięki, powinienem był określić, że to tylko z obserwacji, a nie zrozumienia.
sam boosalis
@ c00kiemon5ter Jak cofnąć set -f? Czy to jest unset -f?
Nam G VU
1
@NamGVUset +f
Yngvar Kristiansen
62

Chociaż prawdą jest, że polecenie samo w sobie nie może wyłączyć globowania, możliwe jest, że użytkownik może powiedzieć powłoce Uniksa, aby nie globowała określonego polecenia. Zwykle jest to osiągane poprzez edycję plików konfiguracyjnych powłoki. Zakładając, że polecenie foomożna znaleźć w ścieżce polecenia, do odpowiedniego pliku konfiguracyjnego należałoby dodać następujące elementy:

W przypadku powłok sh, bash i ksh:

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

W przypadku powłok csh i tcsh:

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

Dla powłoki zsh:

alias foo='noglob foo'

Ścieżka poleceń nie musi być używana. Powiedzmy, że polecenie foo jest przechowywane w katalogu ~ / bin, a powyższe wyglądałoby tak:

W przypadku powłok sh, bash i ksh:

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

W przypadku powłok csh i tcsh:

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

Dla powłoki zsh:

alias foo='noglob ~/bin/foo'

Wszystkie powyższe zostały przetestowane przy użyciu systemu Apple OSX 10.9.2. Uwaga: podczas kopiowania powyższego kodu należy uważać, aby usunąć wszelkie spacje. Mogą być znaczące.

Aktualizacja:

Użytkownik geira zwrócił uwagę, że w przypadku powłoki bash

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

można zastąpić

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

co eliminuje potrzebę funkcji foo.

Niektóre witryny internetowe użyte do utworzenia tego dokumentu:

David Anderson
źródło
3
Powinna to być zaakceptowana odpowiedź, ponieważ dowodzi, że rzeczywiście można robić to, czego chce PO. Dla niektórych nawet lepszych metod w bash, ten link dokumentów różne opcje: blog.edwards-research.com/2011/05/preventing-globbing
geira
@geira: Czasami odpowiedź jest akceptowana przed opublikowaniem lepszej odpowiedzi. Myślę, że to może być jeden z tych przypadków. Uważam również, że znaki odpowiedzi jako najbardziej przydatne dla użytkowników są w pierwszej kolejności. Uwaga: dodałem Twój wpis do mojej odpowiedzi.
David Anderson
@geira, OP chce, aby skompilowany program komunikował się z powłoką; odpowiedź, że można skonfigurować powłokę tak, aby zachowywała się zgodnie z oczekiwaniami na podstawie polecenia po poleceniu, jest użyteczną odpowiedzią i sam bym ją zaakceptował, ale widzę miejsce, w którym mogę się nie zgodzić co do tego, czy jest całkowicie na miejscu.
Charles Duffy
Fakt, że można to zrobić, nie oznacza, że należy to zrobić. Zmiana zachowania powłoki w stosunku do rozsądnych oczekiwań użytkownika dotyczących wybranych poleceń wydaje się zaskakująca i ostatecznie niepożądana.
tripleee
@tripleee: Był czas, kiedy ludzie oczekiwali przekaźników i lamp próżniowych. Spodziewano się dziurkowania w kartach kartonowych i taśmie papierowej. Ludzie trzymali suwaki zamiast kalkulatorów i telefonów. Przypuszczam, że dla ciebie byłoby to pożądane. Nie obchodziły mnie tamte czasy. Lubię patrzeć, co będzie dalej.
David Anderson
8

Rozwinięcie jest wykonywane przez powłokę przed uruchomieniem programu. Twój program nie ma pojęcia, czy nastąpiła ekspansja, czy nie.

   set -o noglob

wyłączy rozwijanie w wywołującej powłoce, ale musisz to zrobić przed wywołaniem programu.

Alternatywą jest cytowanie argumentów np

foo "*"
Brian Agnew
źródło
4
setopt wydaje się być poleceniem specyficznym dla zsh. Jak powiedział inny plakat, dla basha używasz set -o noglobdo wyłączenia ekspansji symboli wieloznacznych.
Wirawan Purwanto
Teraz zmienione. Dziękuję
Brian Agnew
1

Uwaga: jeśli nie ma nazw pasujących do maski, bash przekazuje argument tak, jak jest, bez interpretacji!

Dowód (pa.py to bardzo prosty skrypt, który po prostu wypisuje swoje argumenty):

 $ ls
f1.cc  f2.cc  pa.py
 $ ./pa.py *.cc
['./pa.py', 'f1.cc', 'f2.cc']
 $ ./pa.py *.cpp
['./pa.py', '*.cpp']
lesnik
źródło
3
Nie zawsze. set -o nullgloblub shopt -s failglob, a to zachowanie się zmieni (na dwa bardzo różne sposoby).
Charles Duffy