Szukając ścieżki do pliku wykonywalnego lub sprawdzając, co by się stało, gdybyś wpisał nazwę polecenia w powłoce Uniksa, jest mnóstwo różnych narzędzi ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
itp.).
Często słyszymy, że należy unikać which
. Dlaczego? Czego powinniśmy użyć zamiast tego?
Komentarze
Odpowiedź
Oto wszystko, o czym nigdy nie myślałeś, że nigdy nie chciałbyś o tym wiedzieć:
Podsumowanie
Aby uzyskać nazwa ścieżki do pliku wykonywalnego w skrypcie powłoki podobnym do Bournea (jest kilka zastrzeżeń; patrz poniżej):
ls=$(command -v ls)
Aby dowiedzieć się, czy dane polecenie istnieje:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Po zachęcie interaktywnej powłoki podobnej do Bournea:
type ls
Polecenie which
jest zepsutym dziedzictwem C-Shell i lepiej pozostawić je w spokoju w powłokach podobnych do Bournea.
Użyj przypadków
Tam „to rozróżnienie między szukaniem tych informacji jako części skryptu a interaktywnie w zachęcie powłoki.
Typowy przypadek użycia w linii poleceń wygląda następująco: to polecenie zachowuje się dziwnie, czy używam właściwy? Co dokładnie się stało, gdy wpisałem mycmd
? Czy mogę dokładniej przyjrzeć się temu, co to jest?
W takim przypadku chcesz wiedzieć, co robi twoja powłoka, gdy wywołujesz polecenie bez faktycznego wywoływania polecenia.
W skryptach powłoki wygląda to zupełnie inaczej. W skrypcie powłoki nie ma powodu, dla którego miałbyś chcieć wiedzieć, gdzie lub czym jest polecenie, jeśli chcesz tylko je uruchomić. Ogólnie rzecz biorąc, to, co chcesz wiedzieć, to ścieżka do pliku wykonywalnego, dzięki czemu możesz uzyskać z niego więcej informacji (na przykład ścieżkę do innego pliku względem tego lub odczytać informacje z zawartości pliku wykonywalnego w tej ścieżce).
W trybie interaktywnym możesz chcieć wiedzieć o wszystkich poleceniach my-cmd
dostępnych w systemie, rzadko w skryptach.
Większość dostępnych narzędzi (jak to często bywa) została zaprojektowana do użytku interaktywnego.
Historia
Najpierw trochę historii.
Wczesne powłoki Uniksa aż do późnych lat 70. nie miały żadnych funkcji ani aliasów. Tylko tradycyjne wyszukiwanie plików wykonywalnych w $PATH
. csh
wprowadził aliasy około 1978 r. (chociaż csh
został po raz pierwszy opublikowany w 2BSD
, maj 1979), a także przetwarzanie .cshrc
dla użytkowników w celu dostosowania powłoki (każda powłoka, jak csh
, czyta .cshrc
, nawet jeśli nie jest interaktywny, jak w skryptach).
Podczas gdy powłoka Bourne została po raz pierwszy wydana w Unix V7 wcześniej w 1979 roku, obsługa funkcji została dodana tylko później (1984 w SVR2), a poza tym nigdy nie miał on żadnego pliku rc
(.profile
służy do konfiguracji twojego środowiska, a nie powłoki per se ).
csh
stał się dużo bardziej popularny niż powłoka Bournea, ponieważ (chociaż miał okropnie gorszą składnię niż Bournea) dodawał wiele wygodniejszych i przyjemniejszych funkcji do interaktywnego użytku.
W 3BSD
(1980), which
skrypt csh został dodany dla użytkowników csh
, aby pomóc zidentyfikować plik wykonywalny. Nie jest to prawie inny skrypt, który można znaleźć jako which
na wielu obecnie komercyjnych Uniksach (takich jak Solaris, HP / UX, AIX lub Tru64).
Ten skrypt odczytuje ~/.cshrc
użytkownika (tak jak wszystkie skrypty csh
, chyba że są wywoływane z csh -f
) i wyszukują podane nazwy poleceń na liście aliasów i w $path
(tablicy, którą csh
utrzymuje na podstawie $PATH
).
Proszę bardzo: which
zajął pierwsze miejsce w najpopularniejszej wówczas powłoce (a csh
był nadal popularny do połowy Lat 90.), co jest głównym powodem, dla którego zostało udokumentowane w książkach i nadal jest szeroko stosowane.
Pamiętaj, że nawet dla użytkownika csh
which
skrypt csh niekoniecznie Ci to daje właściwe informacje. Pobiera aliasy zdefiniowane w ~/.cshrc
, a nie te, które mogły zostać zdefiniowane później w monicie lub na przykład przez source
w innym csh
i (choć to nie byłby dobry pomysł) PATH
może zostać przedefiniowane w ~/.cshrc
.
Uruchomienie tego polecenia which
z powłoki Bournea nadal spowoduje wyszukanie aliasów zdefiniowanych w ~/.cshrc
, ale jeśli go nie masz, ponieważ nie używasz csh
, prawdopodobnie dostaniesz właściwą odpowiedź.
Podobna funkcja nie została dodana do powłoka Bournea do 1984 roku w SVR2 z wbudowanym poleceniem type
. Fakt, że jest on wbudowany (w przeciwieństwie do zewnętrznego skryptu) oznacza, że może dostarczyć ci odpowiednich informacji (do pewnego stopnia), ponieważ ma dostęp do wewnętrznych elementów powłoki.
Początkowe polecenie type
miało podobny problem jak skrypt which
, ponieważ nie zwróciło statusu zakończenia błędu, jeśli polecenie nie zostało znalezione. Ponadto w przypadku plików wykonywalnych, w przeciwieństwie do which
, wypisuje coś takiego jak ls is /bin/ls
zamiast tylko /bin/ls
, co czyniło go mniej łatwym w użyciu w skryptach.
Uniksowa wersja 8 (nie wydana na wolności) powłoka Bournea miała to” s type
zmieniono nazwę na whatis
. A Plan9 (niegdyś następca Uniksa) powłoka rc
(i jej pochodne, takie jak akanga
i es
), również mają whatis
.
Powłoka Korna (podzbiór, w którym Definicja POSIX sh
jest oparta na), opracowana w połowie lat 80., ale nie była szeroko dostępna przed 1988 rokiem, dodała wiele funkcji csh
( edytor linii, aliasy …) na wierzchu powłoki Bournea. Dodał własne wbudowane whence
(oprócz type
), które wymagało kilku opcji (-v
w celu udostępnienia pełnych danych wyjściowych type
oraz -p
w celu wyszukania tylko plików wykonywalnych (nie aliasów / funkcji …)) .
Przypadkowo z powodu zamieszania związanego z kwestiami praw autorskich między AT & T i Berkeley, pojawiło się kilka implementacji powłoki wolnego oprogramowania pod koniec lat 80-tych wczesnych 90-tych.Cała powłoka Almquist (ash
, która ma zastąpić powłokę Bournea w BSD), implementacja domeny publicznej ksh
(pdksh
), bash
(sponsorowane przez FSF), zsh
wyszedł między 1989 a 1991.
Ash, chociaż miał być zamiennikiem powłoki Bournea, nie miał wbudowanego type
aż do dużo później (w NetBSD 1.3 i FreeBSD 2.3 ), chociaż miał hash -v
. OSF / 1 /bin/sh
miał wbudowaną type
, która zawsze zwrócono 0 do OSF / 1 v3.x. bash
nie „nie dodałem whence
, ale dodano -p
opcja type
, aby wydrukować ścieżkę (type -p
wyglądałoby następująco: whence -p
) i -a
, aby zgłosić wszystkie pasujące polecenia. tcsh
utworzono which
wbudowane i dodano polecenie where
działające jak bash
” s type -a
. zsh
ma je wszystkie.
fish
shell (2005) ma polecenie type
zaimplementowane jako funkcję.
which
W międzyczasie skrypt csh został usunięty z NetBSD (ponieważ został wbudowany w tcsh i nie był zbyt użyteczny w innych powłokach), a funkcjonalność dodana do whereis
(po wywołaniu jako which
, whereis
zachowuje się jak which
z tą różnicą, że wyszukuje pliki wykonywalne tylko w $PATH
). W OpenBSD i FreeBSD which
również zostało zmienione na napisane w C, które wyszukuje polecenia tylko w $PATH
.
Implementacje
Istnieją dziesiątki implementacji which
co mmand w różnych Uniksach o różnej składni i zachowaniu.
W Linuksie (oprócz wbudowanych w tcsh
i zsh
) znajdujemy kilka realizacji. Na przykład w ostatnich systemach Debian jest to „prosty skrypt powłoki POSIX, który szuka poleceń w $PATH
.
busybox
ma również polecenie which
.
Istnieje GNU
which
, który jest prawdopodobnie najbardziej ekstrawagancki. Próbuje rozszerzyć to, co skrypt which
csh zrobił na inne powłoki: możesz mu powiedzieć, jakie są twoje aliasy i funkcje, aby mógł dać masz lepszą odpowiedź (i uważam, że niektóre dystrybucje Linuksa ustawiają wokół tego aliasy globalne dla bash
, aby to zrobić).
zsh
ma kilka operatorów do rozwinięcia do ścieżki plików wykonywalnych: operator =
rozwinięcie nazwy pliku i :c
modyfikator rozwijania historii (tutaj stosowany do rozwinięcia parametrów ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, w tworzy również tablicę skrótów poleceń jako tablicę asocjacyjną commands
:
$ print -r -- $commands[ls] /bin/ls
Narzędzie whatis
(z wyjątkiem tego w powłoce Unix V8 Bourne lub Planie 9 rc
/ es
) nie jest tak naprawdę powiązany, ponieważ służy tylko do dokumentacji (greps bazy danych whatis, czyli streszczenia strony podręcznika).
whereis
dodane w 3BSD
w tym samym czasie co which
, chociaż zostało napisane w C
, a nie csh
i jest używany do jednoczesnego wyszukiwania pliku wykonywalnego, strony podręcznika i źródła, ale nie w oparciu o bieżące środowisko. Więc znowu, to odpowiada innej potrzebie.
Teraz, na standardowym froncie, POSIX określa command -v
i -V
polecenia (które były opcjonalne do POSIX.2008). UNIX określa polecenie type
(brak opcji). To wszystko (where
, which
, whence
nie są określone w żadnym standardzie) .
Do niektórych wersji type
i command -v
były opcjonalne w specyfikacji Linux Standard Base, co wyjaśnia, dlaczego na przykład niektóre starsze wersje posh
(choć oparte na pdksh
, które miały oba), nie miały żadnego. command -v
został również dodany do niektórych implementacji powłoki Bournea (np. w Solarisie).
Stan na dziś
Obecnie status jest taki, że type
i command -v
są wszechobecne we wszystkich powłoki podobne do Bournea (chociaż, jak zauważył @jarno, zwróć uwagę na zastrzeżenie / błąd w bash
, gdy nie jest w trybie POSIX lub niektórzy potomkowie powłoki Almquist poniżej w komentarzach). tcsh
to jedyna powłoka, w której chciałbyś użyć which
(ponieważ nie ma type
there i which
jest wbudowane).
W powłokach innych niż tcsh
i zsh
, which
może podać ścieżkę do danego pliku wykonywalnego, o ile nie ma aliasu ani funkcji o tej samej nazwie w żadnym z naszych ~/.cshrc
, ~/.bashrc
lub dowolny plik startowy powłoki i nie definiujesz $PATH
w swoim ~/.cshrc
. Jeśli masz zdefiniowany alias lub funkcję, może, ale nie musi, o tym powiedzieć lub powiedzieć niewłaściwą rzecz.
Jeśli chcesz wiedzieć o wszystkich poleceniach o podanej nazwie, nie ma nic przenośnego. Użyjesz where
w tcsh
lub zsh
, type -a
w bash
lub zsh
, whence -a
w ksh93 i innych powłokach , możesz użyć type
w połączeniu z which -a
, co może działać.
Zalecenia
Pobieranie nazwy ścieżki do pliku wykonywalnego
Teraz, aby uzyskać ścieżkę do pliku wykonywalnego w skrypcie, jest kilka zastrzeżeń:
ls=$(command -v ls)
byłby to standardowy sposób.
Jest jednak kilka problemów:
- Nie można poznać ścieżki do pliku wykonywalnego bez jego wykonania. Wszystko
type
,which
,command -v
… wszystkie używają heurystyki, aby znaleźć ścieżkę . W pętli przeglądają komponenty$PATH
i znajdują pierwszy plik niebędący katalogiem, do którego masz uprawnienia do wykonywania. Jednak depe Jeśli chodzi o wykonanie polecenia w powłoce, wiele z nich (Bourne, AT & T ksh, zsh, ash …) po prostu wykona je w kolejności$PATH
do momentu, gdy wywołanie systemoweexecve
nie zwróci błędu. Na przykład, jeśli$PATH
zawiera/foo:/bar
i chcesz wykonaćls
, najpierw spróbują do wykonania/foo/ls
lub jeśli to się nie powiedzie/bar/ls
. Teraz wykonanie/foo/ls
może się nie powieść, ponieważ nie masz uprawnień do wykonywania, ale także z wielu innych powodów, na przykład nie jest to poprawny plik wykonywalny.command -v ls
zgłosi/foo/ls
, jeśli masz uprawnienia do wykonywania/foo/ls
, ale działaszls
może faktycznie działać/bar/ls
, jeśli/foo/ls
nie jest prawidłowym plikiem wykonywalnym. - jeśli
foo
to funkcja wbudowana, funkcja lub alias,command -v foo
zwracafoo
. W przypadku niektórych powłok, takich jakash
,pdksh
lubzsh
, może również zwrócićfoo
jeśli$PATH
zawiera pusty ciąg, aw bieżącym katalogu znajduje się plik wykonywalnyfoo
. W pewnych okolicznościach może być konieczne wzięcie tego pod uwagę. Pamiętaj na przykład, że lista poleceń wbudowanych różni się w zależności od implementacji powłoki (na przykładmount
jest czasami wbudowany w busyboxsh
) i na przykładbash
może pobierać funkcje ze środowiska. - if zawiera komponenty ścieżki względnej (zazwyczaj
.
lub pusty ciąg, który odnosi się do bieżącego katalogu, ale może być cokolwiek) w zależności od powłoki, może nie wyświetlać ścieżki bezwzględnej. Dlatego ścieżka uzyskana podczas uruchamiania przestanie działać pocd
gdzie indziej. - Anegdotal: z powłoką ksh93, jeśli
/opt/ast/bin
(chociaż uważam, że ta dokładna ścieżka może się różnić w różnych systemach) jest w tobie$PATH
, ksh93 udostępni kilka dodatkowych wbudowanych funkcji (chmod
,cmp
,cat
…), alecommand -v chmod
zwróci/opt/ast/bin/chmod
, nawet jeśli ta ścieżka nie istnieje.
Ustalanie, czy polecenie istnieje
Aby dowiedzieć się, czy dane polecenie istnieje standardowo, możesz wykonać:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Gdzie warto użyć which
(t)csh
W csh
i tcsh
nie masz dużego wyboru. W tcsh
„W porządku, ponieważ which
jest wbudowane. W csh
będzie to polecenie systemowe which
, które w kilku przypadkach może nie działać zgodnie z oczekiwaniami.
Znajdź polecenia tylko w niektórych powłokach
Przypadek, w którym może być sensowne użycie which
, to jeśli chcesz znać ścieżkę polecenia, ignorując potencjał wbudowane lub funkcje powłoki w bash
, csh
(nie tcsh
), dash
lub Bourne
skrypty powłoki, czyli powłoki, które nie mają whence -p
(np. ksh
lub zsh
), command -ev
(na przykład yash
), whatis -p
(rc
, akanga
) lub wbudowany which
(np. tcsh
lub zsh
) w systemach, w których which
jest jest dostępny i nie jest csh
.
Jeśli te warunki są spełnione, to:
echo=$(which echo)
poda ścieżkę do pierwszego echo
w $PATH
(z wyjątkiem przypadków narożnych), niezależnie od tego, czy echo
również jest powłoką wbudowany / alias / funkcja czy nie.
W innych powłokach wolisz:
- zsh :
echo==echo
lubecho=$commands[echo]
lubecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(uważaj na ścieżki ze spacjami) - ryba :
set echo (type -fp echo)
Pamiętaj, że jeśli chcesz tylko uruchomić że echo
polecenie, nie musisz określać jego ścieżki, możesz po prostu zrobić:
env echo this is not echoed by the builtin echo
Na przykład z tcsh
, aby zapobiec użyciu wbudowanego which
:
set Echo = "`env which echo`"
Kiedy potrzebujesz zewnętrznego polecenia
Innym przypadkiem, w którym możesz chcieć użyć which
, jest sytuacja, w której faktycznie potrzebujesz polecenie zewnętrzne. POSIX wymaga, aby wszystkie polecenia wbudowane powłoki (takie jak command
) były również dostępne jako polecenia zewnętrzne, ale niestety tak nie jest w przypadku command
na wielu systemach. Na przykład rzadko można znaleźć polecenie command
w systemach operacyjnych opartych na Linuksie, podczas gdy większość z nich ma which
polecenie (choć różne z różnymi opcjami i zachowaniami).
Przypadki, w których możesz potrzebować polecenia zewnętrznego, są wszędzie tam, gdzie wykonasz polecenie bez wywoływania powłoki POSIX.
system("some command line")
, popen()
… funkcje C lub różnych języków wywołują powłokę w celu przeanalizowania tego wiersza poleceń, więc system("command -v my-cmd")
działają w nich. Wyjątkiem byłby perl
, który optymalizuje powłokę, jeśli nie widzi żadnego znaku specjalnego powłoki (innego niż spacja). Dotyczy to również operatora odwrotnego kliknięcia:
$ perl -le "print system "command -v emacs"" -1 $ perl -le "print system ":;command -v emacs"" /usr/bin/emacs 0 $ perl -e "print `command -v emacs`" $ perl -e "print `:;command -v emacs`" /usr/bin/emacs
Dodanie tego :;
powyżej wymusza perl
wywołanie powłoki Tam. Używając which
, nie musiałbyś używać tej sztuczki.
Komentarze
- @Joe,
which
to skryptcsh
na wielu komercyjnych Unikach. Powód jest historyczny, że ' to dlaczego podałem historię, aby ludzie zrozumieli, skąd się wzięła, dlaczego ludzie przyzwyczaili się do jej używania i dlaczego tak naprawdę ' nie ma powodu, żebyś go używał. I tak, niektórzy używają (t) csh. Nie wszyscy jeszcze używają Linuksa. - Po przeczytaniu tego posta znalazłem wiele kontekstu dla odpowiedzi, ale nie znalazłem samej odpowiedzi.W którym miejscu w tym poście faktycznie jest napisane, dlaczego nie używać
which
, w przeciwieństwie do rzeczy, których możesz próbować użyćwhich
do zrobienia, historiawhich
, implementacjewhich
, inne polecenia do wykonania powiązanych zadań lub powody do faktycznego użyciawhich
? Dlaczego inne polecenia są lepsze ? Czym różnią się odwhich
? Jak uniknąć jego pułapek? W tej odpowiedzi więcej słów opisuje problemy z alternatywami niż problemy zwhich
. -
command
jest opisane według POSIX. - @St é phaneChazelas Jeśli utworzę nowy plik przez
touch /usr/bin/mytestfile
, a następnie uruchomię , poda ścieżkę (podczas gdywhich mytestfile
nie). - @jarno, o tak, ' w prawo.
bash
osadzi się na pliku, który nie jest wykonywalny, jeśli nie może ' znaleźć wykonywalnego, więc ' s ” OK ” (choć w praktyce wolałoby sięcommand -v
/type
zwraca błąd), ponieważ ' jest poleceniem, które będzie próbowało wykonać po uruchomieniumytestfile
, ale zachowaniedash
jest błędne, tak jakby ' nie było wykonywalnecmd
przed plikiem wykonywalnym,command -v
zwraca ten, który nie jest wykonywalny, podczas gdy wykonaniecmd
spowodowałoby wykonanie pliku wykonywalnego (niewłaściwy jeden jest również hashowany). FreeBSDsh
(również oparty naash
) ma ten sam błąd. zsh, yash, ksh, mksh, bash as sh są w porządku.
Answer
Powody, dla których można nie chcę używać which
zostało już wyjaśnione, ale oto kilka przykładów na kilku systemach, w których which
faktycznie zawodzi.
W powłokach typu Bourne „porównujemy wynik which
z wynikiem type
(type
jako wbudowana powłoka ma być podstawową prawdą, ponieważ to powłoka mówi nam, jak wywoła polecenie).
Wiele przypadków jest corner sprawy, ale pamiętaj, że which
/ type
są często używane w narożnych przypadkach (aby znaleźć odpowiedź do nieoczekiwanego zachowania, takiego jak: dlaczego do licha to polecenie zachowuje się w ten sposób, do którego dzwonię? ).
Większość systemów, większość powłok podobnych do Bournea: funkcje
Najbardziej oczywisty przypadek dotyczy funkcji:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
Powodem jest to, że which
informuje tylko o plikach wykonywalnych, a czasem o aliasach (choć nie zawsze są to aliasy twojej powłoki), a nie funkcje.
GNU, którego strona podręcznika ma zepsutą (ponieważ zapomnieli zacytować $@
) przykład, jak używać go również do raportowania funkcji, ale tak jak w przypadku aliasy, ponieważ nie implementuje parsera składni powłoki, łatwo go oszukać:
$ which() { (alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@";} $ f() { echo $"\n}\ng ()\n{ echo bar;\n}\n" >> ~/foo; } $ type f f is a function f () { echo " } g () { echo bar; } " >> ~/foo } $ type g bash: type: g: not found $ which f f () { echo " } $ which g g () { echo bar; }
Większość systemów, większość powłok podobnych do Bournea: wbudowane
Innym oczywistym przypadkiem są polecenia wbudowane lub słowa kluczowe, ponieważ which
będąc poleceniem zewnętrznym nie ma sposobu, aby dowiedzieć się, które wbudowane funkcje ma Twoja powłoka (i niektóre powłoki, takie jak zsh
, bash
lub ksh
mogą ładować elementy wbudowane dynamicznie):
$ type echo . time echo is a shell builtin . is a shell builtin time is a shell keyword $ which echo . time /bin/echo which: no . in (/bin:/usr/bin) /usr/bin/time
(to nie ma zastosowania do zsh
, gdzie which
jest wbudowane)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 i wiele innych:
$ csh % which ls ls: aliased to ls -F % unalias ls % which ls ls: aliased to ls -F % ksh $ which ls ls: aliased to ls -F $ type ls ls is a tracked alias for /usr/bin/ls
Dzieje się tak, ponieważ w większości komercyjnych Uniksów which
(jak w oryginalnej implementacji na 3BSD) to csh
skrypt odczytujący ~/.cshrc
. Aliasy, które będzie raportować, to te zdefiniowane tam niezależnie od aliasów, które aktualnie zdefiniowałeś i niezależnie od powłoki, której faktycznie używasz.
W HP / UX lub Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(wersje Solaris i AIX rozwiązały ten problem, zapisując $path
przed przeczytaniem ~/.cshrc
i przywrócenie go przed wyszukaniem poleceń)
$ type "a b" a b is /home/stephane/bin/a b $ which "a b" no a in /usr/sbin /usr/bin no b in /usr/sbin /usr/bin
Lub:
$ d="$HOME/my bin" $ mkdir "$d"; PATH=$PATH:$d $ ln -s /bin/ls "$d/myls" $ type myls myls is /home/stephane/my bin/myls $ which myls no myls in /usr/sbin /usr/bin /home/stephane/my bin
(oczywiście będąc skryptem csh
, nie można oczekiwać, że będzie działał z argumentami zawierającymi spacje …)
CentOS 6.4, bash
$ type which which is aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde" $ alias foo=": "|test|"" $ which foo alias foo=": "|test|"" /usr/bin/test $ alias $"foo=\nalias bar=" $ unalias bar -bash: unalias: bar: not found $ which bar alias bar="
W tym systemie w całym systemie zdefiniowany jest alias, który otacza polecenie GNU which
.
Fałszywe wyjście jest spowodowane tym, że which
odczytuje dane wyjściowe bash
„s alias
ale nie „nie wie, jak to poprawnie przeanalizować i używa heurystyki (jeden alias na wiersz, szuka pierwszego znalezionego polecenia po |
, ;
, &
…)
Najgorsze w CentOS jest to, że zsh
ma idealnie dobre wbudowane polecenie which
, ale CentOS zdołał je złamać, zastępując je niedziałającym aliasem do GNU which
.
Debian 7.0, ksh93:
(chociaż dotyczy większości systemów z wieloma powłokami)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
W Debianie /bin/which
to skrypt /bin/sh
. W moim przypadku sh
jest dash
, ale jest tak samo, gdy jest bash
.
Nierozstawione PATH
nie wyłącza wyszukiwania PATH
, ale oznacza używanie systemowego „s domyślna PATH , na którą niestety w Debianie nikt się nie zgadza (dash
i bash
mają /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
has /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
ma /bin:/usr/bin
, mksh
ma /usr/bin:/bin
($(getconf PATH)
), execvp()
(jak w env
) ma :/bin:/usr/bin
(tak, najpierw szuka w bieżącym katalogu!)) .
Z tego powodu which
źle to widzi powyżej, ponieważ używa domyślnego dash
„identyfikatora
, który różni się od ksh93
„s
Nie t lepiej z GNU which
, który raportuje:
which: no which in ((null))
(co ciekawe, rzeczywiście istnieje /usr/local/bin/which
w moim systemie, który w rzeczywistości jest akanga
skryptem dostarczonym z akanga
(rc
pochodna powłoki, gdzie domyślnym PATH
jest /usr/ucb:/usr/bin:/bin:.
))
bash, dowolny system:
Ten Chris nawiązuje do swojej odpowiedzi :
$ PATH=$HOME/bin:/bin $ ls /dev/null /dev/null $ cp /bin/ls bin $ type ls ls is hashed (/bin/ls) $ command -v ls /bin/ls $ which ls /home/chazelas/bin/ls
Również po ręcznym wywołaniu hash
:
$ type -a which which is /usr/local/bin/which which is /usr/bin/which which is /bin/which $ hash -p /bin/which which $ which which /usr/local/bin/which $ type which which is hashed (/bin/which)
Teraz sprawa, w której which
a czasami type
niepowodzenie:
$ mkdir a b $ echo "#!/bin/echo" > a/foo $ echo "#!/" > b/foo $ chmod +x a/foo b/foo $ PATH=b:a:$PATH $ which foo b/foo $ type foo foo is b/foo
Teraz z niektórymi powłokami:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Z innymi:
$ foo a/foo
Ani which
ani type
może z góry wiedzieć, że b/foo
nie może b został stracony. Niektóre powłoki, takie jak bash
, ksh
lub yash
, podczas wywoływania foo
rzeczywiście spróbuje uruchomić b/foo
i zgłosić błąd, podczas gdy inne (np. zsh
, ash
, csh
, Bourne
, tcsh
) będą działać a/foo
po niepowodzeniu wywołania systemowego execve()
w b/foo
.
Komentarze
-
mksh
w rzeczywistości używa czegoś innego dla domyślnego$PATH
: first , używana jest stała czasu kompilacji systemu operacyjnego_PATH_DEFPATH
(najczęściej w BSD), a następnieconfstr(_CS_PATH, …)
(POSIX), a jeśli oba nie istnieją lub zawiodą, używany jest/bin:/usr/bin:/sbin:/usr/sbin
. - W pierwszym przykładzie, nawet jeśli
ls
jest funkcją, z której korzysta gls
z PATH. Iwhich
wystarczy, aby powiedzieć, który z nich jest używany/usr/bin/ls
czy/usr/local/bin/ls
. Nie ' nie widzę ” Dlaczego nie użyć tego ” …. - @rudimeier, That
which ls
da mi/bin/ls
niezależnie od tego, czyls
wywołania funkcji/bin/ls
lub/opt/gnu/bin/ls
lubdir
albo nic. IOW,which
(te implementacje, IMMV) podaje coś nieistotnego - @St é phaneChazelas. Nie nie nie. Już wiem , że mój
ls
jest funkcją. Wiem , że moja funkcjals
wywołujels
zPATH
. Terazwhich
mówi mi, gdzie jest plik. Widzisz tylko jeden przypadek użycia: ” Co moja powłoka zrobiłaby z tym poleceniem. ” W tym przypadku użyciawhich
jest błędne, prawidłowe.Ale są też inne przypadki użycia, w których (GNU)which
jest dokładnie tym właściwym. - @rudimeter, zależy od
which
implementacja. Niektórzy powiedzą Ci, że ' jest aliasem (jeśli masz skonfigurowany alias lub jeśli w Twoim domu jest~/.cshrc
), który ma taki alias), niektóre podają ścieżkę, ale w pewnych warunkach jest to niewłaściwa.sh -c 'command -v ls'
, chociaż nie jest doskonałe, to jednak bardziej prawdopodobne jest, że da ci właściwą odpowiedź na to inne wymaganie (i jest również standardem).
Odpowiedź
Jedna rzecz, o której (z mojego szybkiego przeglądu) wydaje się, że Stephane nie wspomniał, to to, że which
ma nie mam pojęcia o tablicy hash Twojej powłoki. W rezultacie może zwrócić wynik, który nie jest reprezentatywny dla tego, co faktycznie jest uruchomione, co czyni go nieefektywnym w debugowaniu.
Odpowiedź
Zwykle wzdrygam się, gdy to pytanie jest zalecane niczego niepodejrzewającym użytkownikom, ponieważ bezzasadne atakowanie which
nie jest dla nikogo przydatne.
Jeśli which
działa dobrze i zapewnia poprawną odpowiedź na niektóre zadania, zgodnie z moto Uniksa: zrób jedną rzecz, zrób to dobrze , dlaczego which
zostanie zbanowany?
Pytanie powinno zatem brzmieć, co działa dobrze i dobrze wykonuje określone zadanie?
Po pierwsze, zewnętrzne narzędzie w / bin / które w Debianie jest skryptem powłoki, którego celem jest tylko wyświetlenie w ścieżce plików wykonywalnych o podanej nazwie. Uważam, że which
prawidłowo wykonuje swój zamierzony cel. Nie ładuje żadnych aliasów, żadnych funkcji, nic z powłoki, po prostu wyświetla pierwsze (lub wszystkie) pliki wykonywalne o podanej nazwie w PATH. oznaczające znalezienia pliku o takiej samej nazwie jak podana jest czymś, co użytkownik powinien sam (on) wymyślić siebie.
Tak, inne which
implementacje mogą (i zwykle mają) mieć określone problemy.
Odpowiedź
Często słyszymy o tym, czego należy unikać. Dlaczego? Czego powinniśmy użyć zamiast tego?
Nigdy tego nie słyszałem. Proszę podać konkretne przykłady. Martwiłbym się twoją dystrybucją Linuksa i zainstalowanymi pakietami oprogramowania, ponieważ to skąd pochodzi which
!
SLES 11.4 x86-64
w tcsh w wersji 6.18.01:
> which which which: shell built-in command.
w wersji bash 3.2-147:
> which which /usr/bin/which > which -v GNU which v2.19, Copyright (C) 1999 - 2008 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.
which
jest częścią util-linux to standardowy pakiet dystrybuowany przez Linux Kernel Organization do użytku jako część systemu operacyjnego Linux. Zawiera również te inne pliki
/bin/dmesg /bin/findmnt /bin/logger /bin/lsblk /bin/more /bin/mount /bin/umount /sbin/adjtimex /sbin/agetty /sbin/blkid /sbin/blockdev /sbin/cfdisk /sbin/chcpu /sbin/ctrlaltdel /sbin/elvtune /sbin/fdisk /sbin/findfs /sbin/fsck /sbin/fsck.cramfs /sbin/fsck.minix /sbin/fsfreeze /sbin/fstrim /sbin/hwclock /sbin/losetup /sbin/mkfs /sbin/mkfs.bfs /sbin/mkfs.cramfs /sbin/mkfs.minix /sbin/mkswap /sbin/nologin /sbin/pivot_root /sbin/raw /sbin/sfdisk /sbin/swaplabel /sbin/swapoff /sbin/swapon /sbin/switch_root /sbin/wipefs /usr/bin/cal /usr/bin/chrp-addnote /usr/bin/chrt /usr/bin/col /usr/bin/colcrt /usr/bin/colrm /usr/bin/column /usr/bin/cytune /usr/bin/ddate /usr/bin/fallocate /usr/bin/flock /usr/bin/getopt /usr/bin/hexdump /usr/bin/i386 /usr/bin/ionice /usr/bin/ipcmk /usr/bin/ipcrm /usr/bin/ipcs /usr/bin/isosize /usr/bin/line /usr/bin/linux32 /usr/bin/linux64 /usr/bin/look /usr/bin/lscpu /usr/bin/mcookie /usr/bin/mesg /usr/bin/mkzimage_cmdline /usr/bin/namei /usr/bin/rename /usr/bin/renice /usr/bin/rev /usr/bin/script /usr/bin/scriptreplay /usr/bin/setarch /usr/bin/setsid /usr/bin/setterm /usr/bin/tailf /usr/bin/taskset /usr/bin/time /usr/bin/ul /usr/bin/uname26 /usr/bin/unshare /usr/bin/uuidgen /usr/bin/wall /usr/bin/whereis /usr/bin/which /usr/bin/write /usr/bin/x86_64 /usr/sbin/addpart /usr/sbin/delpart /usr/sbin/fdformat /usr/sbin/flushb /usr/sbin/freeramdisk /usr/sbin/klogconsole /usr/sbin/ldattach /usr/sbin/partx /usr/sbin/rcraw /usr/sbin/readprofile /usr/sbin/rtcwake /usr/sbin/setctsid /usr/sbin/tunelp
mój util-linux
to wersja 2.19. Informacje o wydaniu można łatwo znaleźć w wersji 2.13 z datą (28 sierpnia 2007). Nie jestem pewien, jaki był tego cel lub cel, ale z pewnością nie uzyskał odpowiedzi w tej długiej sprawie, przegłosowanej 331 razy.
Komentarze
- Zwróć uwagę, jak pytanie nie wspomina o tym, do jakiego Uniksa się odnosi. Linux jest tylko jednym z nielicznych.
- Jak pokazuje Twój
which -v
, ' jest GNU, który (ekstrawagancki jeden wymieniony w drugiej odpowiedzi i nie jest w żaden sposób specyficzny dla Linuksa), a nie util-linux, który AFAIK nigdy nie zawierał narzędziawhich
. util-linux 2.19 pochodzi z 2011 r., a GNU 2.19 pochodzi z 2008 r.
which
dotyczy interaktywnego kontekstu powłoki. To pytanie jest oznaczone tagiem / przenośność. Dlatego interpretuję pytanie w tym kontekście jako „, czego użyć zamiastwhich
, aby znaleźć pierwszy plik wykonywalny o podanej nazwie w$PATH
„. Większość odpowiedzi i powodów przeciwwhich
zajmują się aliasami, poleceniami wbudowanymi i funkcjami, które w większości rzeczywistych przenośnych skryptów powłoki są tylko przedmiotem zainteresowania akademickiego. Aliasy zdefiniowane lokalnie nie są dziedziczone ' podczas uruchamiania skryptu powłoki (chyba że źródłem go jest.
).csh
(awhich
to nadalcsh
skrypt w większości reklam Unices) czyta~/.cshrc
w trybie nieinteraktywnym. To ' jest powodem, dla którego ' zauważysz, że skrypty csh zwykle zaczynają się od#! /bin/csh -f
.which
nie, ponieważ ma na celu podanie aliasów, ponieważ ' ma służyć jako narzędzie do (interaktywni) użytkownicycsh
. Użytkownicy powłok POSIX mającommand -v
.(t)csh
(lub nie ' nie masz nic przeciwko, jeśli ' nie daje poprawnego wyniku), użyjtype
lubcommand -v
zamiast tego . Zobacz odpowiedzi, aby dowiedzieć się, dlaczego .stat $(which ls)
jest błędne z kilku powodów (brak--
, brakujące cudzysłowy), a nie tylko użyciewhich
). ' d używaszstat -- "$(command -v ls)"
. Zakłada się, żels
jest rzeczywiście poleceniem znalezionym w systemie plików (nie jest to polecenie wbudowane w powłokę ani funkcja aliasu).which
może podać złą ścieżkę (a nie ścieżkę, którą uruchomiłaby powłoka, gdybyśmy wprowadzilils
) lub alias zgodnie z definicją w konfiguracji niektórych innych powłok …which
implementacji nie zapewniłoby nawetls
, które zostanie znalezione przez wyszukiwanie$PATH
(niezależnie od tego, cols
może wywołać w Twojej powłoce).sh -c 'command -v ls'
lubzsh -c 'rpm -q --whatprovides =ls'
z większym prawdopodobieństwem udzielą poprawnej odpowiedzi. Chodzi o to, żewhich
to zepsute dziedzictwocsh
.