Neden “hangisini” kullanmıyorsunuz? Ne kullanmalı?


328

Bir yürütülebilir yolu arayan veya Unix kabuk içinde bir komut adı girin ne olacağını kontrol ederken, farklı programları bolluğu (var which, type, command, whence, where, whereis, whatis, hash, vs).

Bundan whichkaçınılması gerektiğini sık sık duyuyoruz . Neden? Bunun yerine ne kullanmalıyız?


3
Bence kullanmaya karşı çıkan argümanların çoğu whichetkileşimli bir kabuk bağlamı varsayıyor. Bu soru etiketlendi / taşınabilirlik. Bu yüzden, soruyu bu bağlamda " whichverilen adın ilk çalıştırılabilirini bulmak yerine ne kullanmalıyım" olarak yorumluyorum $PATH. Çoğu whichgerçek dünyada taşınabilir kabuk komut dosyalarında sadece akademik ilgi alanı bulunan takma adlar, yerleşikler ve işlevlerle başa çıkmanın en çok yanıtı ve nedeni . Yerel olarak tanımlanmış diğer adlar, bir kabuk betiği çalıştırılırken miras alınmaz (kaynak göstermediğiniz sürece .).
MattBianco

5
@MattBianco, evet, csh(ve whichhala cshçoğu ticari Unices'de bir komut dosyasıdır) ~/.cshrcetkileşimli olmadığında okur . Bu yüzden csh scriptlerinin genellikle ile başladığını göreceksiniz #! /bin/csh -f. size takma adları vermeyi amaçladığı için whichdeğil , çünkü (etkileşimli) kullanıcıları için bir araç anlamına geliyordu . POSIX, kullanıcıların sahip olduğu kabuklar . cshcommand -v
Stéphane Chazelas

@rudimeier, cevabınız kabuğunuz olmadığı sürece (t)csh(veya size doğru sonucu vermezse sakıncası yoksa), kullanın typeveya command -vkullanın . Neden için cevaplara bakın .
Stéphane Chazelas

1
@ rudimeier, ( stat $(which ls)çeşitli nedenlerden dolayı yanlış (eksik --, eksik tırnak), sadece kullanım için değil which). Kullanırdın stat -- "$(command -v ls)". Bu lsaslında dosya sisteminde bulunan bir komuttur (kabuğunuzun yerleşik değil veya takma işlev). whichyanlış bir yol (girdiğiniz takdirde kabuğunuzun çalıştıracağı yol değil ls) verebilir veya size diğer bazı kabukların yapılandırmasında tanımlandığı gibi bir takma isim verebilir ...
Stéphane Chazelas

1
@ rudimeier, yine, birçok whichuygulamanın size lsbir bakışın bile bulduğu şeyi bile vermeyeceği bir takım koşullar vardır (kabuğunuzda ne yazdırabileceğinden $PATHbağımsız olarak ls). sh -c 'command -v ls'veya zsh -c 'rpm -q --whatprovides =ls'size doğru cevabı verme olasılığı daha yüksektir. Burada mesele şu ki which, kırılmış bir miras csh.
Stéphane Chazelas

Yanıtlar:


366

İşte asla bilmek istemediğini düşündüğün tek şey:

özet

Bir Bourne benzeri kabuk betiğinde çalıştırılabilir bir dosyanın adını almak için (birkaç uyarı vardır; aşağıya bakınız):

ls=$(command -v ls)

Verilen bir komutun olup olmadığını anlamak için:

if command -v given-command > /dev/null 2>&1; then
  echo given-command is available
else
  echo given-command is not available
fi

Etkileşimli bir Bourne benzeri kabuğun isteminde:

type ls

whichKomut C-Shell'den kırık mirasıdır ve daha iyi Bourne benzeri kabuklar yalnız bırakılır.

Durumlarda kullanın

Bu bilgiyi bir betiğin parçası olarak veya kabuk isteminde etkileşimli olarak aramak arasında bir fark vardır.

Kabuk isteminde, tipik kullanım durumu şudur: bu komut garip davranır, ben doğru olanı mı kullanıyorum? Yazarken tam olarak ne oldu mycmd? Ne olduğuna daha fazla bakabilir miyim?

Bu durumda, komutu gerçekten çağırmadan komutu çağırdığınızda kabuğunuzun ne yaptığını bilmek istersiniz.

Kabuk betiklerinde oldukça farklı olma eğilimindedir. Bir kabuk betiğinde, tek yapmak istediğin bir komutun nerede veya ne olduğunu bilmek istemenin bir nedeni yok. Genel olarak bilmek istediğiniz, yürütülebilir dosyanın yoludur, bu nedenle ondan daha fazla bilgi edinebilirsiniz (buna göre başka bir dosyaya giden yol gibi veya bu yoldaki yürütülebilir dosyanın içeriğinden bilgi okuyabilirsiniz).

Etkileşimli, hakkında bilmek isteyebilirsiniz tümmy-cmd nadiren bu yüzden komut sistemi üzerinde kullanılabilir komutlar,.

Mevcut araçların çoğu (çoğu zaman olduğu gibi) etkileşimli olarak kullanılmak üzere tasarlanmıştır.

Tarih

İlk önce biraz tarih.

Erken Unix kabukları, 70'lerin sonlarına kadar hiçbir işlevi ya da takma adı bulunmayana kadar koyar. Sadece geleneksel çalışanlar aranıyor $PATH. csh1978 civarında tanıtılan diğer adları (gerçi cshilk edildi yayımlanan içinde 2BSDayrıca işlenmesini Mayıs 1979,) ve .cshrc(gibi her kabuk kabuk özelleştirmek için kullanıcılar cshokur .cshrcbile değilken interaktif komut gibi).

Bourne kabuğu ilk kez 1979'da Unix V7'de piyasaya sürülürken, işlev desteği çok daha sonra eklendi (1984 SVR2'de), ve yine de hiçbir zaman bir rcdosyaya sahip değildi ( .profileortamınızı yapılandırmak, kabuğunu değil ).

csh Bourne kabuğundan çok daha popüler oldu (Bourne kabuğundan çok daha kötü bir sözdizimine sahip olsa da), etkileşimli kullanım için daha kullanışlı ve hoş özellikler ekliyordu.

In 3BSD(1980), bir whichcsh senaryo için eklenmiş cshbir yürütülebilir belirlemenize yardımcı olmak için kullanıcılara ve siz bulabilirsiniz pek farklı bir senaryo which(Solaris, HP / UX, AIX veya Tru64 gibi) günümüzde birçok ticari Unix'lerde.

Bu komut dosyası, kullanıcının okur ~/.cshrc(tüm cshkomut dosyaları gibi çağrılmaz csh -f) ve sağlanan komut adlarını takma adlar listesinde ve içinde $path( cshtemeli koruyan dizi ) arar $PATH.

İşte whichbaşlıyorsunuz, o zamanlar en popüler kabuk için ilk geldi (ve csh90'lı yılların ortasına kadar hala popülerdi), bu kitaplarda belgelenmesinin ana nedenidir ve hala yaygın olarak kullanılmaktadır.

Bir cshkullanıcı için bile , bu whichcsh betiğinin size doğru bilgileri vermesi gerekmediğini unutmayın. Daha ~/.cshrcsonra istemde tanımladığınızlardan değil, örneğin sourcebaşka bir cshdosyayı kullanarak tanımladığınız takma adları alır ve (bu iyi bir fikir olmasa da) PATHyeniden tanımlanabilir ~/.cshrc.

Bu whichkomutu bir Bourne kabuğundan çalıştırmak, hala sizin için tanımlanmış takma adları arar ~/.cshrc, ancak kullanmadığınız için bir tane yoksa csh, muhtemelen size doğru cevabı verir.

Bourne kabuğuna, typeyerleşik komutla SVR2'de 1984'e kadar benzer bir işlevsellik eklenmedi . O (harici bir komut aksine) yerleşik olduğu gerçeği demektir olabilir o kabuğun iç yapıları erişimi nedeniyle size (bir dereceye kadar) doğru bilgiler vermek.

İlk typekomut, whichkomut bulunmazsa , komut dosyasındaki bir başarısızlık çıkış durumu döndürmediği için benzer bir sorundan muzdaripti . Ayrıca, çalıştırılabilirler için, aksine which, komut dosyalarında kullanımı daha az kolaylaştıran bir şey ls is /bin/lsyerine çıktı /bin/ls.

Unix Versiyon 8'in (vahşi doğada serbest bırakılmadığı) Bourne kabuğunun typeismi değiştirildi whatis. Ve plan9 (Unix kez arası olması halefi) kabuk rc(ve bu gibi türevleri akangave es) sahip whatisde.

80'lerin ortasında geliştirilen ancak 1988'den önce yaygın olarak bulunmayan Korn kabuğu (POSIX sh tanımının dayandığı bir alt küme), cshBourne kabuğunun üstüne birçok özellik (satır düzenleyici, takma ad ...) ekledi. . Birkaç seçenek ( kendi benzeri ayrıntılı çıktı sağlamak ve yalnızca çalıştırılabilir dosyaları aramak için (takma adlar / işlevler ...) değil ) alan kendi whenceyapısını (ek olarak type) ekledi .-vtype-p

AT&T ve Berkeley arasındaki telif hakkı sorunlarıyla ilgili kargaşaya tesadüf eseri, 90'ların başında 80'li yılların sonlarında birkaç ücretsiz yazılım kabuğu uygulaması ortaya çıktı. Almquist kabuğunun tamamı (BSD'lerdeki Bourne kabuğunun yerine konması gereken kül), ksh (pdksh) 'in bash(FSF sponsorluğunda ) kamuya açık uygulaması zsh1989 ve 1991 yılları arasında ortaya çıktı.

Ash, Bourne kabuğunun yerine geçmek anlamına gelse de, typedaha sonraya kadar (NetBSD 1.3 ve FreeBSD 2.3'te) bir yerleşime sahip değildi hash -v. OSF / 1 ' /bin/shin typeher zaman 0' a OSF / 1 v3.x 'e geri dönen bir yapısı vardı. bashbir yol eklemedi, whenceancak yolu yazdırmak ( ister gibi ) ve eşleşen tüm komutları bildirmek için bir -pseçenek ekledi . yapılan yerleşik ve katma gibi hareket komutu 's . hepsine sahip.typetype -pwhence -p-atcshwhichwherebashtype -azsh

fishKabuk (2005) bir sahip typebir fonksiyonu olarak uygulanan komutu.

Bu whicharada csh betiği NetBSD'den (tcsh'de yerleşik olduğu ve diğer mermilerde pek kullanılmadığı) kaldırıldı ve (olarak whereisçağrıldığında which, yalnızca çalıştırılabilir dosyalara bakmadığı whereisgibi davranır) eklenen işlevsellik çıkarıldı . OpenBSD’de ve FreeBSD’de, C’de yazılmış komutları yalnızca komutları arayanlar olarak değiştirdik .which$PATHwhich$PATH

Uygulamalar

whichFarklı sözdizimi ve davranışı olan çeşitli Unices üzerinde bir komutun düzinelerce uygulaması vardır .

Linux'ta (içinde yerleşik olanlar yanında tcshve zsh) biz birkaç uygulamalarını bulabilirsiniz. Örneğin en son Debian sistemlerinde, komutları arayan basit bir POSIX kabuk betiğidir $PATH.

busyboxayrıca bir whichkomut var.

Bir Orada GNU whichmuhtemelen en abartılı biri olan. whichCsh betiğinin diğer kabuklara ne yaptığını genişletmeye çalışır : takma adlarınızın ve işlevlerinizin ne olduğunu söyleyebilirsiniz, böylece size daha iyi bir cevap verebilir (ve bazı Linux dağıtımlarının bunun için bazı küresel takma adlar koyduğuna bashinanıyorum) .

zshçalıştırılabilir yoluna genişletmek için birkaç operatöre sahiptir: = dosya adı genişletme operatörü ve :cgeçmiş genişletme değiştiricisi (burada parametre genişletmeye uygulanır ):

$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls

zsh, zsh/parametersmodülde ayrıca komut commandsdizisi ilişkisel dizi olarak tablo yapar :

$ print -r -- $commands[ls]
/bin/ls

Yardımcı whatisprogram (Unix V8 Bourne kabuğundaki veya Plan 9 rc/ ' esdakiler hariç ) gerçekten sadece dokümantasyon için geçerli değildir (whatis veritabanını, man sayfası özeti olan whatis veritabanını tutar).

whereisAyrıca eklendi 3BSDaynı zamanda whicho yazılmış olsa C, değil csh, aynı zamanda, içinde bulundukları ortama göre yürütülebilir, adam sayfası ve kaynak ama hiç de arama için kullanılır. Yani yine, bu farklı bir ihtiyaca cevap veriyor.

Şimdi, standart ön tarafta, POSIX command -vve -Vkomutlarını belirtir (hangi POSIX.2008'e kadar isteğe bağlıydı). UNIX typekomutu belirtir (seçenek yok). Yani hepsi ( where, which, whenceherhangi bir standart belirtilmeyen)

Bazı sürümlere kadar typeve command -vörneğin bazılarının eski sürümlerinin posh( pdkshikisine de sahip olmasına rağmen ) neden olmadığını açıklayan Linux Standard Base spesifikasyonunda isteğe bağlıydı . command -vbazı Bourne kabuğu uygulamalarına (Solaris'teki gibi) de eklendi.

Bugünün Durumu

Bugünlerde durum şu typeve command -vtüm Bourne benzeri mermilerde her yerde bulunmakta (her ne kadar @jarno tarafından belirtildiği gibi bash, POSIX modunda değilken veya yorumlarda aşağıdaki Almquist kabuğunun bazı torunları). tcshkullanmak isteyeceğiniz tek kabuktur which(çünkü orada yoktur typeve whichyerleşiktir).

Dışındaki kabukları içinde tcshve zsh, whichsürece hiçbir ad veya işlev aynı isimle kızımız hiçbirinde olduğu gibi size verilen yürütülebilir yolunu söyleyebilir ~/.cshrc, ~/.bashrcya da herhangi bir kabuk başlatma dosyası ve tanımlamaz $PATHGözlerinde farklı ~/.cshrc. Tanımlanmış bir takma adınız veya işleviniz varsa, bu konuda size söyleyebilecek ya da söylemeyebilir veya yanlış bir şey söyleyebilirsiniz.

Tüm komutları belirli bir adla bilmek istiyorsanız, taşınabilir bir şey yok. Sen kullanmayı tercih wherebölgesi tcshveya zsh, type -aiçinde bashya zsh, whence -aksh93 ve diğer kabuklarda kullanabileceğiniz typebirlikte which -ahangi çalışabilir.

öneriler

Yol adını çalıştırılabilir dosyaya alma

Şimdi, bir betiğin çalıştırılabilir kodunun adını almak için birkaç uyarı var:

ls=$(command -v ls)

Bunu yapmanın standart yolu olurdu.

Ancak birkaç sorun var:

  • Çalıştırılabilir dosya yolunu, çalıştırmadan bilmek mümkün değildir. Tüm type, which, command -v... tüm kullanım sezgiselleri yolunu bulmak için. Onlar aracılığıyla döngü $PATHbileşenleri ve yürütme iznine sahip olan ilk dizin olmayan dosyasını bulun. Bununla birlikte, kabuğa bağlı olarak, komut çalıştırıldığında, birçoğu (Bourne, AT&T ksh, zsh, ash ...) sistem çağrısı bir hata ile dönmeyene $PATHkadar onları sadece yürütecektir. execve. Örneğin, $PATHiçeriyorsa /foo:/barve yürütmek istiyorsanız ls, önce yürütmeye çalışacaklar /foo/lsveya başarısız olursa /bar/ls. Şimdi yürütme/foo/lsYürütme izniniz olmadığından ancak geçerli bir çalıştırılabilir olmadığından başka nedenlerden dolayı başarısız olabilir. için yürütme izniniz varsa command -v lsrapor /foo/lseder /foo/ls, ancak geçerli bir lsçalıştırılabilir /bar/lsdeğilse /foo/ls, çalıştırma işlemi gerçekten çalışabilir .
  • Eğer foobir yerleşik ya da fonksiyon ya da diğer adı olan, command -v foodöner foo. Boş dizgiyi içeriyorsa ve geçerli dizinde çalıştırılabilir bir dosya varsa ash, pdkshveya gibi bazı kabuklarda zshda döndürülebilir . Bunu dikkate almanız gerekebilecek bazı durumlar vardır. Örneğin, yerleşiklerin listesinin kabuk uygulamasına bağlı olduğunu unutmayın (örneğin, bazen meşgul kutusu için yerleşiktir ) ve örneğin ortamdan işlevler alabilir.foo$PATHfoomountshbash
  • Eğer $PATH(tipik olarak göreceli yol bileşenleri içeren .ya da her ikisi geçerli dizine bakınız başka bir şey olabilir boş dize), kabuk bağlı command -v cmdolabilir çıkış mutlak bir yolu. Bu nedenle koşarken elde ettiğiniz yol, başka bir yerden command -vsonra geçerli cdolmayacaktır.
  • Anekdot: eğer ksh93 kabuk ile, /opt/ast/bin(yani tam yol inanıyorum farklı sistemlerde farklı olabilir gerçi) senin içinde $PATH, ksh93 mevcut birkaç ekstra yerleşiklerinden (yapacaktır chmod, cmp, cat...), ama command -v chmoddönecektir /opt/ast/bin/chmodo yolun kokan bile t var.

Bir komutun olup olmadığını belirleme

Belirli bir komutun standart olarak olup olmadığını öğrenmek için şunları yapabilirsiniz:

if command -v given-command > /dev/null 2>&1; then
  echo given-command is available
else
  echo given-command is not available
fi

Nerede kullanmak istersin? which

(t)csh

İçinde cshve tcshfazla seçeneğiniz yok. İçinde tcsholduğu gibi iyidir which. Bu csh, whichbirkaç durumda istediğiniz şeyi yapamayabileceğiniz sistem komutu olacaktır .

komutları sadece bazı mermilerde bul

Kullanmanın mantıklı olabileceği bir durum which, bir komutun yolunu bilmek, potansiyel kabuk yapılarını veya işlevlerini bash, csh(değil tcsh) dashya da Bournekabuk komut dosyalarında yok sayarak whence -p(gibi kshya da zsh) kabuk komut dosyalarını görmezden gelmek isteyip istemediğinizdir. , command -ev(like yash), whatis -p( rc, akanga) veya mevcut olan ve script olmayan sistemlerdeki bir yerleşik which(like tcshveya zsh) .whichcsh

Bu koşullar yerine getirilirse, o zaman:

echo=$(which echo)

Size ilk yolunu verecekti echoiçinde $PATH(köşe durumlar haricinde) ne olursa olsun, olsun echoda bir kabuk yerleşik / takma / fonksiyon ya da olmamak olur.

Diğer kabuklarda, tercih edersiniz:

  • zsh : echo==echoveya echo=$commands[echo]veyaecho=${${:-echo}:c}
  • ksh , zsh :echo=$(whence -p echo)
  • yaş :echo=$(command -ev echo)
  • rc , akanga : echo=`whatis -p echo`(boşluklu yollara dikkat et)
  • balık :set echo (type -fp echo)

Yapmanız gereken tek şey bu komutu çalıştırmak ise echo, onun yolunu almak zorunda değilsiniz, sadece şunu yapabilirsiniz:

env echo this is not echoed by the builtin echo

Örneğin tcsh, yerleşimin whichkullanılmasını önlemek için :

set Echo = "`env which echo`"

harici bir komuta ihtiyaç duyduğunuzda

Kullanmak isteyebileceğiniz başka bir durum which, aslında harici bir komuta ihtiyaç duyduğunuzda olabilir . POSIX, tüm kabuk yerleşiklerinin (gibi command) harici komutlar olarak da kullanılabilmesini gerektirir , ancak ne yazık ki commandpek çok sistem için geçerli değildir . Örneğin command, Linux tabanlı işletim sistemlerinde bir komut bulmak nadirdir which( birçoğunda bir komut olsa da (farklı seçenekler ve davranışlar içeren farklı olsalar)).

Harici bir komut isteyebileceğiniz durumlar, bir POSIX kabuğunu çağırmadan bir komutu yerine getireceğiniz her yerde olur.

system("some command line"), popen()... C veya çeşitli dillerde yerine getirdiği işlevleri komut satırı ayrıştırmak için bir kabuk çağırmak, böylece do system("command -v my-cmd")onları çalışma yapmak. Bunun bir istisnası, perlherhangi bir özel kabuk karakteri (boşluk dışında) görmezse, kabuğu en iyi duruma getirmesi olabilir . Bu aynı zamanda backtick operatörü için de geçerlidir:

$ 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

Yukarıdakilerin eklenmesi, orada bir kabuk çağırmaya :;zorlar perl. Kullanarak which, bu numarayı kullanmak zorunda kalmazsınız.


24
@Joe, birçok ticari Unices'de whichbir cshsenaryo. Sebep tarihseldir, bu yüzden tarihi verdim, bu yüzden insanlar nereden geldiğini, neden kullanmaya alıştıklarını ve aslında kullanmanız için hiçbir neden olmadıklarını anlıyorlar. Ve evet, bazı insanlar (t) csh kullanıyor. Henüz herkes Linux
kullanmıyor

12
Bu yazıyı okuduktan sonra, cevap için çok fazla bağlam buldum, ancak cevabın kendisinde değil. Nerede bu yazı aslında neden yazıyor değil kullanmak whichKullanmak çalışıyor olabilir şeylerin aksine, whichyapmak tarihçesi which, uygulamalarını which, diğer ilgili görevleri yapmak komutları veya fiilen kullanmak nedenlerle which? Diğer komutlar neden daha iyi ? Bundan farklı ne yapıyorlar which? Tuzaklarından nasıl kaçınırlar? Bu cevap aslında alternatiflerle ilgili problemlere problemlerden daha fazla kelime harcıyor which.
user62251

1
Cevabın iddia ettiği şeyin aksine command -v, en azından yolu olmayan salt dosya adı argümanı ile çağırırsanız, yürütme iznini kontrol etmez. Dash 0.5.8 ve GNU bash 4.3.48 ile test ettim.
jarno

2
@ StéphaneChazelas Eğer touch /usr/bin/mytestfileve sonrasında çalıştırıp yeni bir dosya oluşturursam command -v mytestfile, yolunu verir (oysa which mytestfiledeğil).
jarno

2
@ jarno, oh evet, haklısın. bashEğer çalıştırılabilir bir dosya bulamazsa, çalıştırılamaz bir dosyaya yerleşir, bu yüzden "Tamam" (pratikte bir hata vermeyi tercih eder command -v/ typegeri döndürür), çünkü çalıştırdığınızda çalıştırmaya çalıştığı komut budur mytestfile, ancak dashdavranışı, cmdçalıştırılabilir olanın önünde çalıştırılabilir olmayan bir dosya varmış gibi command -vyürütülür cmd, çalıştırılabilir çalıştırılabilir dosyayı çalıştırırken çalıştırılamaz olanı döndürür (yanlış olan da hashed olur). FreeBSD sh(ayrıca dayanarak ash) aynı hatayı vardır. zsh, yash, ksh, mksh, sh kadar bash tamam.
Stéphane Chazelas,

47

Birinin kullanmak istememesinin nedenleri whichzaten açıklanmıştır, ancak burada whichgerçekten başarısız olan birkaç sisteme birkaç örnek verilmiştir .

Bourne benzeri mermilerde, çıktısının whichçıktısını type( typebir kabuk yerleşimi olmak, bunun bir emre nasıl çağrıştıracağını söyleyen kabuk olduğu gibi) temel gerçek olmaktır) ile karşılaştırıyoruz.

Çoğu durumda köşe kasaları vardır, ancak köşe kasalarında sıkça kullanıldığını which/ typebeklenmedik bir davranışın cevabını bulmak için kullanılır: neden bu komut böyle davranıyor, neden birini arıyorum? ).

Çoğu sistem, çoğu Bourne benzeri kabuk: fonksiyonlar

En belirgin durum işlevler içindir:

$ type ls
ls is a function
ls ()
{
[ -t 1 ] && set -- -F "$@";
command ls "$@"
}
$ which ls
/bin/ls

Bunun nedeni olmak which(değil her zaman olanları olsa takma adları hakkında bazen sadece yürütülebilir hakkında raporlar ve senin değil, işlevleri kabuk).

Man sayfasının (alıntı yapmayı unuttukları gibi $@) bozuk olduğu GNU, fonksiyonları rapor etmek için nasıl kullanılacağına dair bir örnek verir, ancak sadece takma adlar için olduğu gibi, bir kabuk sözdizimi ayrıştırıcısı uygulamadığı için kolayca kandırılır:

$ 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;
}

Çoğu sistem, çoğu Bourne benzeri kabuk: yerleşik

Olarak Bariz bir başka vaka, builtins veya anahtar kelimeleri olduğunu whichda kabuk var yerleşiklerini bilmenin bir yolu vardır (ve benzeri bazı kabukları harici komut olma zsh, bashya da kshdinamik olarak yerleşiklerini yükleyebilirsiniz):

$ 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

(bu yerleşik zsholduğu whichyer için geçerli değildir )

Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5.1 ve diğerleri:

$ 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

Bunun nedeni çoğu ticari whichUnice'de (3BSD'deki orijinal uygulamada olduğu gibi) cshokuyan bir komut dosyası olmasıdır ~/.cshrc. Raporlayacağı takma adlar, o anda tanımladığınız takma adlardan bağımsız olarak ve gerçekte kullandığınız kabuktan bağımsız olarak burada tanımlanmış olanlardır.

HP / UX veya Tru64'te:

% echo 'setenv PATH /bin:/usr/bin' >> ~/.cshrc
% setenv PATH ~/bin:/bin:/usr/bin
% ln -s /bin/ls ~/bin/
% which ls
/bin/ls

(Solaris ve AIX sürümleri, $pathokumadan önce kaydederek ~/.cshrcve komutları aramadan önce geri yükleyerek bu sorunu çözmüştür)

$ 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

Veya:

$ 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

(elbette, bir cshkomut dosyası olmak, boşluk içeren argümanlarla çalışmasını bekleyemezsiniz ...)

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='

Bu sistemde, GNU whichkomutunu saran sistem çapında tanımlanmış bir takma ad vardır .

Sahte çıktı çünkü whichçıkışı okur bashs' aliasama düzgün ayrıştırmak bilmiyor ve buluşsal yöntemlerini kullanır (her satıra bir diğer adı ilk olarak bir sonraki komutu bulundu arar |, ;, &...)

CentOS'taki en kötü şey, zshkusursuz bir whichyerleşik komuta sahip olmasıdır, ancak CentOS, çalışmayan bir takma adıyla GNU'ya değiştirerek onu kırmayı başardı which.

Debian 7.0, ksh93:

(yine de birçok mermi bulunan sistemlere uygulanır)

$ unset PATH
$ which which
/usr/local/bin/which
$ type which
which is a tracked alias for /bin/which

Debian'da /bin/whichbir /bin/shsenaryo. Benim durumumda sholmak, dashama olduğu zaman aynı bash.

Bir tanımsız PATHdevre dışı bırakmak için değil PATHarama, ancak sistemin kullanmak anlamına varsayılan PATH maalesef Debian, kimse üzerinde hemfikir ( dashve bashvarsa /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, zshvardır /bin:/usr/bin:/usr/ucb:/usr/local/bin, ksh93vardır /bin:/usr/bin, mkshvardır /usr/bin:/bin( $(getconf PATH),) execvp()gibi ( env) vardır :/bin:/usr/binevet, ilk geçerli dizinde arar (! )).

Bu yüzden mi whichyanlış o kullanıyor beri yukarıda onu alır dash'ın varsayılan PATHfarklıdır ksh93s'

whichRapor eden GNU ile daha iyi değil :

which: no which in ((null))

(ilginç bir şekilde, aslında /usr/local/bin/whichsistemde bir akangakomut dosyası olan akanga( rcvarsayılanın PATHolduğu bir kabuk türevi) gelen bir komut dosyası var. /usr/ucb:/usr/bin:/bin:.)

bash, herhangi bir sistem:

Tek Chris onun cevabını atıfta olduğunu :

$ 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

Ayrıca hashmanuel olarak aradıktan sonra :

$ 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)

Şimdi whichve bazen typebaşarısız olduğu bir durum :

$ 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

Şimdi, bazı mermilerle:

$ foo
bash: ./b/foo: /: bad interpreter: Permission denied

Diğerleriyle:

$ foo
a/foo

Ne yürütülemeyeceğini ne whichde typeönceden bilemez b/foo. Bazı kabuklar gibi bash, kshya da yash, çağrılırken foogerçekten çalıştırmayı dener b/foodiğerleri (gibi iken ve bir hata bildirir zsh, ash, csh, Bourne, tcsh) çalışacak a/fooarızalanması üzerine execve()sistem çağrısı b/foo.


mkshaslında varsayılan için farklı bir şey kullanır $PATH: ilk önce işletim sisteminin derleme zamanı sabiti _PATH_DEFPATHkullanılır (en yaygın olarak BSD'lerde), sonra confstr(_CS_PATH, …)kullanılır (POSIX) ve eğer ikisi de yoksa veya başarısız olursa /bin:/usr/bin:/sbin:/usr/sbinkullanılır.
mirabilos,

1
İlk örnekte PATH'ten lskullandığı bir fonksiyon olsa bile ls. Ve whichhangisinin kullanıldığını /usr/bin/ls veya hangisinin kullanıldığını söylemek sorun değil /usr/local/bin/ls. "Neden hangisini kullanmıyorsun?"
Göremiyorum

@rudimeier That which lsbeni verecektir /bin/lsbakılmaksızın ait lsfonksiyon çağrıları /bin/lsveya /opt/gnu/bin/lsveya dirhiç bir şey ya. IOW, which(ki bu uygulama, IMMV) alakasız bir şey veriyor
Stéphane Chazelas

1
@ StéphaneChazelas. Hayır hayır hayır. Ben biliyorum benim zaten lsbir işlevdir. Ben biliyorum benim bu lsfonksiyon çağırıyor lsdan PATH. Şimdi whichbana dosyanın yerini söyle. Yalnızca bir tek kullanımlık durum görürsünüz: "Kabuğum bu komutla ne yapardı?" Bu kullanım için durum whichyanlış, doğru. Ancak (GNU) whichtam olarak doğru olan başka kullanım durumları da vardır .
rudimeier

@ rudimetre, whichuygulamaya bağlıdır . Bazıları size bunun bir takma ad olduğunu söyleyecektir (yapılandırılmış bir takma ~/.cshrcadınız varsa veya evinizde böyle bir takma adı olan bir tane varsa), bazıları size bazı koşullar altında yanlış olanı verecektir. sh -c 'command -v ls'Yine de mükemmel olmamakla birlikte, size bu farklı gereksinime (ve ayrıca standart) doğru cevabı verme olasılığı daha yüksektir.
Stéphane Chazelas,

21

Stephane'un bahsetmediği bir şey (çabuk kaymağımdan) which, kabuğunun yolundaki hash masası hakkında hiçbir fikrinin olmadığı gibi görünüyor . Bu, gerçekte neyin çalıştırıldığını temsil etmeyen ve hata ayıklamada etkisiz hale getiren bir sonucu geri getirme etkisine sahiptir.


6

UNIX ruhunda: Her programın bir şeyi iyi yapmasını sağlayın.

Amaç cevap vermekse: Bu isimde hangi yürütülebilir dosya var ?

Debian sistemleri ile sağlanan çalıştırılabilir program iyi bir cevaptır. Csh ile sağlanan takma adları içeriyordu, bu bir sorun kaynağı. Bazı mermilerin iç yapı olarak sağladıkları farklı bir hedefe sahiptir. Bu yürütülebilir dosyayı kullanın veya bu yanıtın sonunda verilen komut dosyasını kullanın.

Bu komut dosyası kullanılıyorsa, cevap verdiği şey temiz, basit ve kullanışlıdır.

Bu hedef, sorunuzun ilk cümlesiyle eşleşecektir:

Yürütülebilir dosyanın yolunu ararken……

Eğer (çoğu linux sisteminde bir tane vardır) adında bir çalıştırılabilir dosyası bulunmayan bir sisteminiz varsa , PATH içinde daha ~/bin/whichönce bir tane oluşturabilirsiniz /bin/, böylece kişisel çalıştırılabilir geçersiz kılma sistemi bu yazının altındaki sistemler gibi:

Bu yürütülebilir dosya PATH'ta bulunan tüm yürütülebilir dosyaları (varsayılan olarak) listeler . Sadece ilki gerekliyse, seçenek -fkullanılabilir.


Bu noktada farklı bir hedefe düşüyoruz:

Kabuğun ne yapacağını (ayrıştırdıktan sonra)

Bu senin ikinci cümleden geliyor:

Unix kabuğuna bir komut adı girerseniz ne olacağını kontrol etme

Bu ikinci konu, cevaplaması oldukça zor olan bir soruya iyi bir cevap bulmaya çalışır. Kabuklar farklı görüşlere, köşe çantalara ve (en azından) farklı yorumlara sahiptir. Buna ekleyerek:

farklı yararların bir bolluğu var (bu, yazın, komut, niçin, nerede, nerede, nerede, hash, vb.).

Ve elbette, tüm girişimler bu hedefe uygun.


Hangisinden kaçının?

Kaçınılması gereken şeyleri sık sık duyuyoruz.

Merak ediyorum: İyi çalışıyorsa neden söylenmeli which(en azından debian'da)?

UNIX ruhunda: Her programı iyi bir şey yapsın.

Dış programı whichbir şeyi yapıyor: aynı ada sahip PATH ilk yürütülebilir bulun komut adı . Ve oldukça iyi yapıyor.

Bu soruya daha temel bir şekilde cevap veren başka bir program veya yardımcı program bilmiyorum. Bu nedenle, faydalıdır ve gerektiğinde kullanılabilir.

En yakın alternatif görünmektedir: command -pv commandNameancak bu, yerleşikler ve takma adlar hakkında da rapor verecektir. Aynı cevap değil.

Elbette which, sınırlıdır, tüm soruları cevaplamaz , hiçbir araç bunu yapamaz (peki, henüz değil ...). Ancak, cevaplamak için tasarlandığı soruyu cevaplamak için kullanıldığında yararlıdır (hemen yukarıdaki soru). Gibi edçok sınırlı ve sonra sedortaya çıktı (veya vi/ vim). Veya benzeri awksınırlıydı ve Perl'in görünüp uzamasını sağladı. Oysa ed, sedve / veya awknerede belirli kullanım durumları vimveya perlolan değil iyi araçlar.

Neden?

Muhtemelen whichbir kabuk kullanıcısının sorabileceği sorunun yalnızca bir kısmına cevap verdiğinden:

Bir commandName yazdığımda ne yürütülüyor?


Dış hangi

Harici bir çalıştırılabilir olarak mevcut olması gereken (birçok sistemde).
Bu dış aracı çağırmanın tek kesin yolu, env'yi kabuktan çıkıp sonra çağırmaktır which(tüm kabuklarda çalışır):

 $ env which which
 /usr/bin/which

Veya which(farklı sistemlerde değişebilir) için tam yolu kullanın :

 /usr/bin/which which 

Bu neden hackgerekli? Çünkü bazı kabukları (özellikle zsh) gizler which:

 $ zsh -c 'which which'
 which: shell built-in command

Dış bir araç (gibi env) olmak , neden kabuk iç bilgilerini rapor etmeyeceğini açıklar. Diğer adlar, işlevler, yerleşikler, özel yerleşikler, kabuk (dışa aktarılmayan) değişkenler vb.

 $ env which ls
 /usr/bin/ls
 $ env which ll       # empty output

ll(Ortak bir takma adın ll='ls -l') boş çıktısının llçalıştırılabilir bir programla ilgili olmadığını veya en azından llPATH'de adlandırılan çalıştırılabilir bir dosya olmadığını gösterir . Kullanımı, llbu durumda başka bir ad vermelidir:

 $ type ll
 ll is aliased to `ls -l'

type ve command

Komutlar typeve command -vPOSIX tarafından talep edilir. Çoğu kabukta çalışması beklenir ve csh, tcsh, fish ve rc hariç yapmaları gerekir.

Her iki komut da, komutun yürütüleceği başka bir bakış açısı sağlamak için kullanılabilir.

whence, where, whereis, whatis,hash

Sonra, orada whence, where, whereis, whatis, hash, ve diğerleri. Benzer sorulara verilen tüm farklı cevaplar. Hepsi farklı mermilerde farklı şekillerde çalışır. Muhtemelen, whencesonradan en yaygın olanıdır type. Diğerleri aynı soruyu farklı şekillerde cevaplayan özel çözümlerdir.

Bunun yerine ne kullanmalıyız?

Muhtemelen whichadında bir yürütülebilir mevcutsa ilk bilmek CommandName sonra typeve commandeğer ve sonra CommandName : Henüz bulunamamıştır whence, where, whereis, whatis, hashbu sırayla.


Shell betiği whichçalıştırılabilir sağlamak için .

#! /bin/sh
set -ef; oldIFS=$IFS; IFS=:

say()( IFS=" "; printf "%s\n" "$*"; )
say "Simplified version of which."
usage(){ say Usage: "$0" [-f] args; }
if [ "$#" -eq 0 ]; then say Missing argument(s); usage; exit 2; fi

firstmatch=0
while getopts f whichopts; do
    case "$whichopts" in
        f) firstmatch=1 ;;
        ?) usage; exit 3 ;;
    esac
done
[ "$OPTIND" -gt 1 ] && shift `expr "$OPTIND" - 1`

allret=0; [ "$#" -eq 0 ] && allret=1
for program in "$@"; do
    ret=1
    for element in $PATH''; do
        case "$program" in
            */*) element="$program"; loop=0;;
            *)   element="${element:-.}/$program"; loop=1;;
        esac
        if [ -f "$element" ] && [ -x "$element" ]; then
            say "$element"
            ret=0
            if [ "$firstmatch" -eq 1 ] || [ "$loop" -eq 0 ]; then break; fi
        fi
    done
    [ "$ret" -eq 1 ] && allret=1
done

IFS="$oldIFS"
exit "$allret"

0

Kaçınılması gereken şeyleri sık sık duyuyoruz. Neden? Bunun yerine ne kullanmalıyız?

Bunu hiç duymamıştım. Lütfen özel örnekler veriniz. Linux dağıtımınız ve kurulu yazılım paketleriniz için endişeliyim, whichgeldiği yerden!

SLES 11,4 x 86-64

tcsh versiyonunda 6.18.01:

> which which

which: shell built-in command.

bash versiyon 3.2-147’de:

> 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.

whichbir parçası olan util-Linux Linux işletim sisteminin bir parçası olarak kullanıma yönelik Linux Çekirdek Örgütü tarafından dağıtılan standart bir paket. Ayrıca bu diğer dosyaları sağlar

/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

benim util-linuxsürüm 2.19. Sürüm notları kolayca 282 Ağustos 2007 tarihli v2.13 bulunabilir. Bunun amacı ya da amacının ne olduğundan emin değiliz, 331 kez oylanan o uzun şeyde kesinlikle cevaplanmadı.


2
Sorunun, hangi Unix'e gönderme yaptığından bahsetmediğine dikkat edin. Linux birkaç kişiden sadece biri.
Kusalananda

2
Senin gibi which -vşovlar, o (savurgan bir başka cevapta belirtildiği ve Linux özgü hiçbir şekilde) GNU AFAIK bir yer asla değil Util-linux var whichyarar. util-Linux 2.19, 2011, 2008 ila 2.19 GNU
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.