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 which
komenda 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-cmd
poleceń 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
. csh
wprowadzono aliasy około 1978 r. (chociaż csh
po raz pierwszy wydano w 2BSD
maju 1979 r.), a także przetwarzanie .cshrc
dla użytkowników w celu dostosowania powłoki (każda powłoka, jak csh
czyta się, .cshrc
nawet 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ś rc
plik ( .profile
jest 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 which
skrypt csh dla csh
użytkowników, aby pomóc zidentyfikować plik wykonywalny, i jest to prawie inny skrypt, jaki można obecnie znaleźć which
w wielu komercyjnych Unices (takich jak Solaris, HP / UX, AIX lub Tru64).
Ten skrypt odczytuje użytkownika ~/.cshrc
(tak jak wszystkie csh
skrypty, chyba że jest wywoływany csh -f
) i wyszukuje podane nazwy poleceń na liście aliasów i $path
(w tablicy, która csh
utrzymuje się na podstawie $PATH
).
Proszę bardzo, which
w tym czasie pojawiła się pierwsza najpopularniejsza powłoka (i csh
był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 csh
użytkownika ten which
skrypt 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 source
innego csh
pliku, i (choć nie byłoby to dobrym pomysłem) PATH
może zostać ponownie zdefiniowane ~/.cshrc
.
Uruchomienie tego which
polecenia 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 type
wbudowanym 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 type
komenda napotkała podobny problem jak which
skrypt, 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 which
tego, wypisuje coś podobnego ls is /bin/ls
zamiast tego, /bin/ls
co czyni go łatwiejszym w użyciu w skryptach.
Uniksowa wersja 8 (nie wydana na wolności) Powłoka Bourne'a, której type
nazwa wbudowana została zmieniona na whatis
. Powłoka Plan9 (niegdyś następca Uniksa) rc
(i jej pochodne jak akanga
i 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 csh
funkcji (edytor linii, aliasy ...) na wierzchu powłoki Bourne'a . Dodał własne whence
wbudowane (oprócz type
), które wzięło kilka opcji ( -v
aby zapewnić type
pełne, podobne wyjście, i -p
szukać 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), zsh
pojawiła się w latach 1989-1991.
Ash, choć miał być zamiennikiem powłoki Bourne'a, nie miał type
wbudowanej wersji dużo później (w NetBSD 1.3 i FreeBSD 2.3), chociaż tak było hash -v
. OSF / 1 /bin/sh
miał type
wbudowane narzędzie, które zawsze zwracało 0 do OSF / 1 v3.x. bash
nie dodał, whence
ale dodał -p
opcję type
drukowania ścieżki ( type -p
byłoby jak whence -p
) i -a
zgłaszania wszystkich pasujących poleceń. tcsh
wykonany which
wbudowane i dodaje where
polecenie działając jak bash
„s type -a
. zsh
ma je wszystkie.
fish
Shell (2005) ma type
polecenia realizowane jako funkcja.
which
Csh 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
, whereis
zachowuje się which
poza tym, że tylko wyszukuje pliki wykonywalne w $PATH
). W OpenBSD i FreeBSD which
zmieniono również na jeden napisany w C, który wyszukuje tylko polecenia $PATH
.
Realizacje
Istnieją dziesiątki implementacji which
polecenia na różnych Uniksach o różnej składni i zachowaniu.
W systemie Linux (oprócz wbudowanych w tcsh
i zsh
) znajdujemy kilka implementacji. Na przykład w najnowszych systemach Debian jest to prosty skrypt powłoki POSIX, który szuka poleceń w $PATH
.
busybox
ma również which
polecenie.
Jest taki, GNU
which
który jest prawdopodobnie najbardziej ekstrawagancki. Próbuje rozszerzyć to, co which
skrypt 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
) .
zsh
ma kilka operatorów do rozszerzenia ścieżki do plików wykonywalnych: operator =
rozwijania nazw plików i :c
modyfikator rozszerzania historii (tutaj stosowany do rozszerzania parametrów ):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh
, w zsh/parameters
module tworzy również tablicę skrótów poleceń jako commands
tablicę asocjacyjną:
$ print -r -- $commands[ls]
/bin/ls
whatis
Gospodarczy (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).
whereis
został również dodany w 3BSD
tym samym czasie, which
jakby został napisany C
, csh
a 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 -v
i -V
(które były opcjonalne do POSIX.2008). UNIX określa type
polecenie (brak opcji). To wszystko ( where
, which
, whence
nie są określone w dowolnym standardzie)
Do niektórych wersji type
i command -v
były opcjonalne w specyfikacji Linux Standard Base, która wyjaśnia, dlaczego na przykład niektóre stare wersje posh
(choć oparte na pdksh
których miały obie) nie miały żadnej z nich. command -v
został również dodany do niektórych implementacji powłoki Bourne'a (takich jak Solaris).
Status dzisiaj
Obecnie status jest taki type
i command -v
są one wszechobecne we wszystkich powłokach podobnych do Bourne'a (jednak, jak zauważył @jarno, zwróć uwagę na zastrzeżenie / błąd, bash
gdy nie jest w trybie POSIX lub niektórzy potomkowie powłoki Almquist poniżej w komentarzach). tcsh
jest jedyną powłoką, w której chciałbyś użyć which
(ponieważ jej nie type
ma i which
jest wbudowana).
W muszli innych niż tcsh
i zsh
, which
moż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
, ~/.bashrc
lub dowolny plik startowy powłoki i nie określają $PATH
w 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ć where
w tcsh
lub zsh
, type -a
w bash
lub zsh
, whence -a
w ksh93 i innych skorup, można używać type
w połączeniu z which -a
któ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 $PATH
komponenty 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, $PATH
dopóki execve
wywołanie systemowe nie powróci z błędem . Na przykład, jeśli $PATH
zawiera /foo:/bar
i chcesz wykonać ls
, najpierw spróbują wykonać /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, np. nie jest to prawidłowy plik wykonywalny. command -v ls
zgłosi, /foo/ls
jeśli masz uprawnienia do wykonywania /foo/ls
, ale uruchomienie ls
może faktycznie działać, /bar/ls
jeśli /foo/ls
nie jest prawidłowym plikiem wykonywalnym.
- jeśli
foo
jest wbudowaną funkcją lub aliasem, command -v foo
zwraca foo
. Przy czym niektóre muszle podoba ash
, pdksh
czy zsh
może również wrócić foo
jeśli $PATH
zawiera pusty ciąg i jest wykonywalny foo
plik 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 mount
czasami jest wbudowana dla busyboksa sh
) i na przykład bash
może pobierać funkcje ze środowiska.
- jeśli
$PATH
zawiera 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 cmd
moż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 cd
gdzie 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 chmod
wróci /opt/ast/bin/chmod
nawet 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 csh
i tcsh
nie masz dużego wyboru. W tcsh
jest w porządku, jak which
jest wbudowane. W csh
będzie to which
polecenie 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ć which
jest, jeśli chcesz poznać ścieżkę polecenia, pomijając potencjalne poleceń wbudowanych powłoki lub funkcji bash
, csh
(nie tcsh
), dash
lub Bourne
skryptów powłoki, czyli powłoki, które nie mają whence -p
(jak ksh
lub zsh
) , command -ev
(jak yash
), whatis -p
( rc
, akanga
) lub wbudowany which
(jak tcsh
lub zsh
) w systemach, w których which
jest dostępny i nie jest csh
skryptem.
Jeśli te warunki są spełnione, to:
echo=$(which echo)
dałby ci ścieżkę pierwszego echo
w $PATH
(z wyjątkiem przypadków narożnych), niezależnie od tego, czy echo
zdarza się, że jest to wbudowana powłoka / alias / funkcja czy nie.
W innych powłokach wolisz:
- zsh :
echo==echo
lub 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 echo
polecenie, nie musisz uzyskać jego ścieżki, możesz po prostu zrobić:
env echo this is not echoed by the builtin echo
Na przykład, tcsh
aby uniemożliwić which
użycie wbudowanego :
set Echo = "`env which echo`"
kiedy potrzebujesz zewnętrznego polecenia
Innym przypadkiem, w którym możesz chcieć użyć, which
jest 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 command
w wielu systemach. Na przykład rzadko zdarza się znaleźć command
polecenie w systemach operacyjnych opartych na systemie Linux, podczas gdy większość z nich ma which
polecenie (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, perl
któ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 perl
do wywołania tam skorupy. Korzystając z tej opcji which
, nie musisz używać tej sztuczki.
which
zakłada interaktywny kontekst powłoki. To pytanie jest oznaczone / przenośne. Tak więc interpretuję pytanie w tym kontekście jako „czego użyć zamiastwhich
znaleźć pierwszy plik wykonywalny danej nazwy w$PATH
”. Większość odpowiedzi i powodówwhich
przemawiają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.
).