Oto wszystko, o czym nigdy nie pomyślałeś, że nigdy nie chcesz o tym wiedzieć:
Podsumowanie
Aby uzyskać nazwę ścieżki pliku wykonywalnego w skrypcie powłoki podobnym do Bourne'a (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 Bourne'a:
type ls
Ta whichkomenda jest zepsutym dziedzictwem z C-Shell i lepiej zostawić ją samą w muszlach podobnych do Bourne'a.
Przypadków użycia
Istnieje rozróżnienie między wyszukiwaniem tych informacji jako części skryptu lub interaktywnym po zachęcie powłoki.
W wierszu poleceń typowym przypadkiem użycia jest: to polecenie zachowuje się dziwnie, czy używam właściwego? Co dokładnie się stało, kiedy pisałem mycmd? Czy mogę przyjrzeć się temu, co to jest?
W takim przypadku chcesz wiedzieć, co robi twoja powłoka, kiedy 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 chciałbyś wiedzieć, gdzie lub czym jest polecenie, jeśli wszystko, co chcesz zrobić, to uruchomić je. Ogólnie rzecz biorąc, chcesz wiedzieć o ścieżce pliku wykonywalnego, dzięki czemu możesz uzyskać więcej informacji (np. Ścieżkę do innego pliku w stosunku do tego lub odczytać informacje z zawartości pliku wykonywalnego przy tej ścieżce).
Interaktywnie, może chcesz wiedzieć o wszystkich tych my-cmdpoleceń dostępnych w systemie, w skryptach, rzadko tak.
Większość dostępnych narzędzi (jak to często bywa) została zaprojektowana do interaktywnego używania.
Historia
Najpierw trochę historii.
Wczesne powłoki uniksowe do późnych lat 70. nie miały żadnych funkcji ani aliasów. Tylko tradycyjne wyszukiwanie plików wykonywalnych w $PATH. cshwprowadzono aliasy około 1978 r. (chociaż cshpo raz pierwszy wydano w 2BSDmaju 1979 r.), a także przetwarzanie .cshrcdla użytkowników w celu dostosowania powłoki (każda powłoka, jak cshczyta się, .cshrcnawet jeśli nie jest interaktywna, jak w skryptach).
natomiast Bourne shell został po raz pierwszy wydany w Unix V7 wcześniej w 1979 roku, wsparcie funkcja została tylko dodaje dużo później (1984 w SVR2), a w każdym razie, nigdy nie miałem jakiś rcplik ( .profilejest do skonfigurowania środowiska, nie powłoce per se ).
csh zyskał znacznie większą popularność niż powłoka Bourne'a, ponieważ (choć miał strasznie gorszą składnię niż powłoka Bourne'a), dodawał wiele wygodniejszych i przyjemniejszych funkcji do interaktywnego użytku.
W 3BSD(1980) dodano whichskrypt csh dla cshużytkowników, aby pomóc zidentyfikować plik wykonywalny, i jest to prawie inny skrypt, jaki można obecnie znaleźć whichw wielu komercyjnych Unices (takich jak Solaris, HP / UX, AIX lub Tru64).
Ten skrypt odczytuje użytkownika ~/.cshrc(tak jak wszystkie cshskrypty, chyba że jest wywoływany csh -f) i wyszukuje podane nazwy poleceń na liście aliasów i $path(w tablicy, która cshutrzymuje się na podstawie $PATH).
Proszę bardzo, whichw tym czasie pojawiła się pierwsza najpopularniejsza powłoka (i cshbyła popularna do połowy lat 90.), co jest głównym powodem, dla którego została udokumentowana w książkach i jest nadal szeroko stosowana.
Zauważ, że nawet dla cshużytkownika ten whichskrypt csh niekoniecznie dostarcza ci właściwych informacji. Pobiera zdefiniowane aliasy ~/.cshrc, a nie te, które mogłeś zdefiniować później w monicie lub na przykład poprzez umieszczenie sourceinnego cshpliku, i (choć nie byłoby to dobrym pomysłem) PATHmoże zostać ponownie zdefiniowane ~/.cshrc.
Uruchomienie tego whichpolecenia z powłoki Bourne'a nadal szukałoby aliasów zdefiniowanych w twoim ~/.cshrc, ale jeśli nie masz takiego, ponieważ go nie używasz csh, prawdopodobnie nadal dostaniesz właściwą odpowiedź.
Podobna funkcjonalność została dodana do powłoki Bourne'a dopiero w 1984 roku w SVR2 z typewbudowanym poleceniem. Fakt, że jest on wbudowany (w przeciwieństwie do zewnętrznego skryptu) oznacza, że może on dostarczyć odpowiednich informacji (do pewnego stopnia), ponieważ ma dostęp do wewnętrznych elementów powłoki.
Początkowa typekomenda napotkała podobny problem jak whichskrypt, ponieważ nie zwróciła statusu wyjścia błędu, jeśli komenda nie została znaleziona. Ponadto w przypadku plików wykonywalnych, w przeciwieństwie do whichtego, wypisuje coś podobnego ls is /bin/lszamiast tego, /bin/lsco czyni go łatwiejszym w użyciu w skryptach.
Uniksowa wersja 8 (nie wydana na wolności) Powłoka Bourne'a, której typenazwa wbudowana została zmieniona na whatis. Powłoka Plan9 (niegdyś następca Uniksa) rc(i jej pochodne jak akangai es) również mają whatis.
Powłoka Korna (podzbiór, na którym opiera się definicja sh POSIX), opracowana w połowie lat 80., ale nie szeroko dostępna przed 1988 r., Dodała wiele cshfunkcji (edytor linii, aliasy ...) na wierzchu powłoki Bourne'a . Dodał własne whencewbudowane (oprócz type), które wzięło kilka opcji ( -vaby zapewnić typepełne, podobne wyjście, i -pszukać tylko plików wykonywalnych (nie aliasów / funkcji ...).
Zbieg okoliczności w związku z zawirowaniami dotyczącymi praw autorskich między AT&T i Berkeley, kilka implementacji powłoki wolnego oprogramowania pojawiło się pod koniec lat 80. na początku lat 90. Cała skorupa Almquista (jesion, która ma zastąpić powłokę Bourne'a w BSD), publiczna implementacja ksh (pdksh) bash(sponsorowana przez FSF), zshpojawiła się w latach 1989-1991.
Ash, choć miał być zamiennikiem powłoki Bourne'a, nie miał typewbudowanej wersji dużo później (w NetBSD 1.3 i FreeBSD 2.3), chociaż tak było hash -v. OSF / 1 /bin/shmiał typewbudowane narzędzie, które zawsze zwracało 0 do OSF / 1 v3.x. bashnie dodał, whenceale dodał -popcję typedrukowania ścieżki ( type -pbyłoby jak whence -p) i -azgłaszania wszystkich pasujących poleceń. tcshwykonany whichwbudowane i dodaje wherepolecenie działając jak bash„s type -a. zshma je wszystkie.
fishShell (2005) ma typepolecenia realizowane jako funkcja.
whichCsh skrypt tymczasem został usunięty z NetBSD (jak to było wbudowane w tcsh i nie wiele wykorzystania w innych powłok) oraz funkcjonalność dodana do whereis(gdy wywołany jako which, whereiszachowuje się whichpoza tym, że tylko wyszukuje pliki wykonywalne w $PATH). W OpenBSD i FreeBSD whichzmieniono również na jeden napisany w C, który wyszukuje tylko polecenia $PATH.
Realizacje
Istnieją dziesiątki implementacji whichpolecenia na różnych Uniksach o różnej składni i zachowaniu.
W systemie Linux (oprócz wbudowanych w tcshi zsh) znajdujemy kilka implementacji. Na przykład w najnowszych systemach Debian jest to prosty skrypt powłoki POSIX, który szuka poleceń w $PATH.
busyboxma również whichpolecenie.
Jest taki, GNU whichktóry jest prawdopodobnie najbardziej ekstrawagancki. Próbuje rozszerzyć to, co whichskrypt csh zrobił na inne powłoki: możesz powiedzieć, jakie są twoje aliasy i funkcje, aby dać ci lepszą odpowiedź (i wierzę, że niektóre dystrybucje Linuksa ustawiają wokół tego globalne aliasy bash) .
zshma kilka operatorów do rozszerzenia ścieżki do plików wykonywalnych: operator = rozwijania nazw plików i :cmodyfikator rozszerzania historii (tutaj stosowany do rozszerzania parametrów ):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh, w zsh/parametersmodule tworzy również tablicę skrótów poleceń jako commandstablicę asocjacyjną:
$ print -r -- $commands[ls]
/bin/ls
whatisGospodarczy (z wyjątkiem jednego w Unix V8 Bourne shell lub planu 9 rc/ es) tak naprawdę nie jest związane, jak to tylko dokumentacja (greps bazę whatis, że jest człowiekiem strona streszczenie).
whereiszostał również dodany w 3BSDtym samym czasie, whichjakby został napisany C, csha nie służy do wyszukiwania w tym samym czasie pliku wykonywalnego, strony podręcznika i źródła, ale nie w oparciu o bieżące środowisko. Znów odpowiada to na inną potrzebę.
Teraz, na standardowym froncie, POSIX określa polecenia command -vi -V(które były opcjonalne do POSIX.2008). UNIX określa typepolecenie (brak opcji). To wszystko ( where, which, whencenie są określone w dowolnym standardzie)
Do niektórych wersji typei command -vbyły opcjonalne w specyfikacji Linux Standard Base, która wyjaśnia, dlaczego na przykład niektóre stare wersje posh(choć oparte na pdkshktórych miały obie) nie miały żadnej z nich. command -vzostał również dodany do niektórych implementacji powłoki Bourne'a (takich jak Solaris).
Status dzisiaj
Obecnie status jest taki typei command -vsą one wszechobecne we wszystkich powłokach podobnych do Bourne'a (jednak, jak zauważył @jarno, zwróć uwagę na zastrzeżenie / błąd, bashgdy nie jest w trybie POSIX lub niektórzy potomkowie powłoki Almquist poniżej w komentarzach). tcshjest jedyną powłoką, w której chciałbyś użyć which(ponieważ jej nie typema i whichjest wbudowana).
W muszli innych niż tcshi zsh, whichmożna powiedzieć, ścieżkę danego pliku wykonywalnego, tak długo jak nie ma pseudonim lub funkcja o tej samej nazwie, w każdym z naszych ~/.cshrc, ~/.bashrclub dowolny plik startowy powłoki i nie określają $PATHw twojej ~/.cshrc. Jeśli masz dla niego zdefiniowany alias lub funkcję, może ci o tym powiedzieć lub nie, lub powiedzieć coś niewłaściwego.
Jeśli chcesz wiedzieć o wszystkich poleceniach pod danym imieniem, nie ma nic przenośnego. Można by użyć wherew tcshlub zsh, type -aw bashlub zsh, whence -aw ksh93 i innych skorup, można używać typew połączeniu z which -aktórych mogą pracować.
Rekomendacje
Uzyskiwanie nazwy ścieżki do pliku wykonywalnego
Teraz, aby uzyskać ścieżkę do pliku wykonywalnego w skrypcie, istnieje kilka zastrzeżeń:
ls=$(command -v ls)
byłby to standardowy sposób na zrobienie tego.
Istnieje jednak kilka problemów:
- Nie można poznać ścieżki pliku wykonywalnego bez jego wykonania. Wszyscy
type, which, command -v... wszystkie heurystyki użytku, aby dowiedzieć się ścieżki. Przechodzą przez $PATHkomponenty i znajdują pierwszy plik inny niż katalog, dla którego masz uprawnienia do wykonania. Jednak w zależności od powłoki, jeśli chodzi o wykonanie polecenia, wiele z nich (Bourne, AT&T ksh, zsh, ash ...) po prostu wykona je w kolejności, $PATHdopóki execvewywołanie systemowe nie powróci z błędem . Na przykład, jeśli $PATHzawiera /foo:/bari chcesz wykonać ls, najpierw spróbują wykonać /foo/lslub jeśli to się nie powiedzie /bar/ls. Teraz wykonanie/foo/lsmoże się nie powieść, ponieważ nie masz uprawnień do wykonywania, ale także z wielu innych powodów, np. nie jest to prawidłowy plik wykonywalny. command -v lszgłosi, /foo/lsjeśli masz uprawnienia do wykonywania /foo/ls, ale uruchomienie lsmoże faktycznie działać, /bar/lsjeśli /foo/lsnie jest prawidłowym plikiem wykonywalnym.
- jeśli
foojest wbudowaną funkcją lub aliasem, command -v foozwraca foo. Przy czym niektóre muszle podoba ash, pdkshczy zshmoże również wrócić foojeśli $PATHzawiera pusty ciąg i jest wykonywalny fooplik w bieżącym katalogu. Istnieją pewne okoliczności, w których może to być konieczne. Pamiętaj na przykład, że lista wbudowanych elementów różni się w zależności od implementacji powłoki (na przykład mountczasami jest wbudowana dla busyboksa sh) i na przykład bashmoże pobierać funkcje ze środowiska.
- jeśli
$PATHzawiera względne komponenty ścieżki (zazwyczaj .lub pusty ciąg, które oba odnoszą się do bieżącego katalogu, ale mogą być czymkolwiek), w zależności od powłoki, command -v cmdmoże nie generować ścieżki bezwzględnej. Tak więc ścieżka, którą uzyskasz w czasie biegu command -v, nie będzie już ważna po tobie cdgdzie indziej.
- Niepotwierdzone: z powłoką ksh93, jeśli
/opt/ast/bin(choć że dokładna ścieżka może być różna w różnych systemach wierzę) jest w was $PATH, ksh93 udostępni kilka dodatkowych builtins ( chmod, cmp, cat...), ale command -v chmodwróci /opt/ast/bin/chmodnawet jeśli ścieżka robi” istnieje.
Ustalanie, czy polecenie istnieje
Aby dowiedzieć się, czy dane polecenie istnieje standardowo, możesz:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
Gdzie można chcieć użyć which
(t)csh
W cshi tcshnie masz dużego wyboru. W tcshjest w porządku, jak whichjest wbudowane. W cshbędzie to whichpolecenie systemowe , które może nie zrobić tego, co chcesz w kilku przypadkach.
znajdź polecenia tylko w niektórych powłokach
Przypadek, w którym może ona sensu używać whichjest, jeśli chcesz poznać ścieżkę polecenia, pomijając potencjalne poleceń wbudowanych powłoki lub funkcji bash, csh(nie tcsh), dashlub Bourneskryptów powłoki, czyli powłoki, które nie mają whence -p(jak kshlub zsh) , command -ev(jak yash), whatis -p( rc, akanga) lub wbudowany which(jak tcshlub zsh) w systemach, w których whichjest dostępny i nie jest cshskryptem.
Jeśli te warunki są spełnione, to:
echo=$(which echo)
dałby ci ścieżkę pierwszego echow $PATH(z wyjątkiem przypadków narożnych), niezależnie od tego, czy echozdarza się, że jest to wbudowana powłoka / alias / funkcja czy nie.
W innych powłokach wolisz:
- zsh :
echo==echolub echo=$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)
- ryby :
set echo (type -fp echo)
Zauważ, że jeśli wszystko, co chcesz zrobić, to uruchomić to echopolecenie, nie musisz uzyskać jego ścieżki, możesz po prostu zrobić:
env echo this is not echoed by the builtin echo
Na przykład, tcshaby uniemożliwić whichużycie wbudowanego :
set Echo = "`env which echo`"
kiedy potrzebujesz zewnętrznego polecenia
Innym przypadkiem, w którym możesz chcieć użyć, whichjest to, kiedy faktycznie potrzebujesz zewnętrznego polecenia. POSIX wymaga, aby wszystkie wbudowane powłoki (podobnie jak command) były również dostępne jako polecenia zewnętrzne, ale niestety tak nie jest commandw wielu systemach. Na przykład rzadko zdarza się znaleźć commandpolecenie w systemach operacyjnych opartych na systemie Linux, podczas gdy większość z nich ma whichpolecenie (choć różne z różnymi opcjami i zachowaniami).
Przypadki, w których możesz chcieć użyć zewnętrznego polecenia, znajdowałyby się wszędzie tam, gdzie wykonywałbyś polecenie bez wywoływania powłoki POSIX.
system("some command line"), popen()... Funkcje C lub różnych językach nie wywołuje powłokę do analizowania tego wiersza polecenia, więc system("command -v my-cmd")wykonywać pracę w nich. Wyjątkiem byłby ten, perlktóry optymalizuje powłokę, jeśli nie widzi żadnego specjalnego znaku powłoki (innego niż spacja). Dotyczy to również jego operatora zwrotnego:
$ 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 zmusza perldo wywołania tam skorupy. Korzystając z tej opcji which, nie musisz używać tej sztuczki.
whichzakłada interaktywny kontekst powłoki. To pytanie jest oznaczone / przenośne. Tak więc interpretuję pytanie w tym kontekście jako „czego użyć zamiastwhichznaleźć pierwszy plik wykonywalny danej nazwy w$PATH”. Większość odpowiedzi i powodówwhichprzemawiających przeciwko aliasom, wbudowanym funkcjom i funkcjom, które w większości przenośnych skryptów powłoki w świecie rzeczywistym są przedmiotem zainteresowania akademickiego. Lokalnie zdefiniowane aliasy nie są dziedziczone podczas uruchamiania skryptu powłoki (chyba że zostanie to za pomocą źródła.).