Miksi et käytä “ joka ”? Mitä sitten käytetään?

Kun etsit polkua suoritettavaan tiedostoon tai tarkistat mitä tapahtuisi, jos annat komennon nimen Unix-kuoreen, siellä on lukuisia erilaisia apuohjelmia ( which, type, command, whence, where, whereis, whatis, hash jne.).

Kuulemme usein, että which tulisi välttää. Miksi? Mitä meidän pitäisi käyttää sen sijaan?

Kommentit

  • Luulen, että useimmat argumentit, jotka vastustavat which -käyttöä, ovat interaktiivisen kuoren kontekstin. Tämä kysymys on merkitty / siirrettävyys. Joten tulkitsen kysymys tässä kontekstissa nimellä ” mitä käyttää which: n sijasta etsimään tietyn nimen ensimmäinen suoritettava tiedosto kohdasta $PATH ”. Useimmat vastaukset ja syyt vastaan which käsittelevät aliaksia, sisäänrakennettuja tiedostoja ja toimintoja, joista useimmissa reaalimaailman kannettavissa komentotiedostosarjoissa on vain akateemista merkitystä. Paikallisesti määriteltyjä aliaksia ei ’ t peritä, kun suoritetaan komentosarjakomentosarja (ellet lähde sitä .).
  • @MattBianco, kyllä, csh (ja which on edelleen komento csh useimmissa kaupallisissa kohteissa Unices) lukee ~/.cshrc, kun se ei ole vuorovaikutteinen. Siksi ’ s, miksi ’ ll huomaa csh-komentosarjat alkavat yleensä #! /bin/csh -f. which ei, koska se pyrkii antamaan sinulle aliaksia, koska se ’ on tarkoitettu työkaluksi csh (vuorovaikutteiset) käyttäjät. POSIX-kuorien käyttäjillä on command -v.
  • @rudimeier, vastaus olisi aina, ellei kuori ole (t)csh (tai et ’ ole mielessä, jos se ei anna ’ t antaa sinulle oikean tuloksen), käytä type tai command -v sen sijaan . Katso vastaukset miksi .
  • @rudimeier, (stat $(which ls) on väärä useista syistä (puuttuu --, lainausmerkit puuttuvat), ei pelkästään which). ’ käytät stat -- "$(command -v ls)". Tämä olettaa, että ls on todellakin tiedostojärjestelmästä löydetty komento (ei kuoren sisäänrakennettu osa tai aliaksen toiminto). which saattaa antaa sinulle väärän polun (ei polun, jonka komentotulkki suorittaa, jos syötät ls) tai antaa sinulle määritetyn aliaksen joidenkin muiden kuorien kokoonpanossa …
  • @rudimeier, on jälleen olemassa useita ehtoja, joissa monet which -toteutukset eivät antaisi sinulle edes ls, joka löydetään hakemalla $PATH (riippumatta siitä, mitä ls voi vedota kuoressasi). sh -c 'command -v ls' tai zsh -c 'rpm -q --whatprovides =ls' antaa todennäköisemmin oikean vastauksen. Tässä on se, että which on rikki perintö, joka on peräisin csh.

Vastaa

Tässä on kaikki mitä et koskaan ajatellut, ettet koskaan halua tietää siitä:

Yhteenveto

Saat Bourne-tyyppisessä shell-komentosarjassa suoritettavan suoritettavan tiedoston polku (muutamia varoituksia; katso alla):

ls=$(command -v ls) 

Voit selvittää, onko annettu komento:

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

Interaktiivisen Bourne-tyyppisen kuoren kehotteessa:

type ls 

which -komento on rikki C-Shellin perintö, ja se on parempi jättää yksin Bournen kaltaisiin kuoreisiin.

Käytä tapauksia

Siellä ”Ero näiden tietojen etsimisen osana komentosarjaa tai vuorovaikutteisesti komentokehotteessa.

Kuorikehotteessa tyypillinen käyttötapaus on: tämä komento käyttäytyy oudosti, käytänkö oikea? Mitä tapahtui, kun kirjoitin mycmd? Voinko tarkastella tarkemmin, mitä se on?

Siinä tapauksessa haluat tietää, mitä komentotulkki tekee, kun käynnistät komennon käynnistämättä komentoa.

Kuoriskripteissä se on yleensä melko erilainen. Shell-komentosarjassa ei ole mitään syytä, miksi haluat tietää, missä tai mikä komento on, jos haluat vain suorittaa sen. Yleensä mitä haluat tietää, on suoritettavan tiedoston polku, joten voit saada siitä enemmän tietoja (kuten toisen tiedoston polku verrattuna siihen tai lukea tietoja kyseisen polun suoritettavan tiedoston sisällöstä).

Vuorovaikutteisesti saatat haluta tietää kaikista järjestelmässä käytettävissä olevista my-cmd -komennoista skripteinä, harvoin niin.

Suurin osa käytettävissä olevista työkaluista (kuten usein tapahtuu) on suunniteltu käytettäväksi vuorovaikutteisesti.

Historia

Ensin vähän historiaa.

Varhaisissa Unix-kuorissa 70-luvun loppupuolelle saakka ei ollut toimintoja tai aliaksia. Vain perinteinen suoritettavien tiedostojen haku hakemistossa $PATH. csh esitteli aliaksia noin 1978 (vaikka csh julkaistiin ensin julkaistuna kohdassa 2BSD, toukokuussa 1979), ja myös .cshrc -prosessin käsittely käyttäjille kuoren mukauttamiseksi (jokainen kuori, kuten csh , lukee .cshrc silloinkin, kun se ei ole vuorovaikutteinen kuten komentosarjoissa).

Vaikka Bourne-kuori julkaistiin ensimmäisen kerran Unix V7: ssä aiemmin vuonna 1979, toimintojen tuki lisättiin vain paljon myöhemmin (1984 SVR2: ssa), ja joka tapauksessa sillä ei koskaan ollut rc -tiedostoa (.profile on määritettävä ympäristö, ei kuori per se ).

csh sai paljon suositumpaa kuin Bourne-kuori, koska (vaikka sen syntaksit olivat hirvittävän huonommat kuin Bourne-kuori), se lisäsi paljon mukavampia ja mukavampia ominaisuuksia vuorovaikutteiseen käyttöön.

3BSD (1980) -lehdessä which csh -komentosarja lisättiin csh -käyttäjille helpottamaan suoritettavaa tiedostoa, ja se on tuskin erilainen skripti, jonka löydät nimellä which nykyään monissa kaupallisissa laitteissa (kuten Solaris, HP / UX, AIX tai Tru64).

Tämä komentosarja lukee käyttäjän” s ~/.cshrc (kuten kaikki csh -skriptit tekevät, ellei niitä kutsuta csh -f -toiminnolla), ja etsii annetut komentojen nimet aliaksiluettelosta ja ryhmässä $path (taulukko, jota csh ylläpitää $PATH perusteella).

Täällä: which oli tuolloin suosituimman kuoren ensimmäinen (ja csh oli edelleen suosittu 90-luvulla), mikä on tärkein syy siihen, miksi se dokumentoitiin kirjoissa ja jota käytetään edelleen laajalti.

Huomaa, että csh -käyttäjälle, id = ”9b39b47e6e”>

csh-komentosarja ei välttämättä anna sinulle oikeat tiedot. Se saa aliakset, jotka on määritelty kohdassa~/.cshrc, ei niitä, jotka olet määrittänyt myöhemmin kehotteessa tai esimerkiksisourcemuodostamalla toisencsh-tiedosto, ja (vaikka se ei olekaan hyvä idea),PATHvoidaan määritellä uudelleen osastossa~/.cshrc.

Tämän which -komennon suorittaminen Bourne-kuoresta haisi silti ~/.cshrc -palvelussa määritettyjä aliaksia, mutta jos sinulla ei ole sellaista, koska et käytä csh, se todennäköisesti saisi oikean vastauksen.

Vastaavaa toimintoa ei lisätty Bourne-kuori vuoteen 1984 SVR2: ssa sisäänrakennetulla type -komennolla. Se, että se on sisäänrakennettu (toisin kuin ulkoinen komentosarja), tarkoittaa, että se voi antaa sinulle oikeat tiedot (jossain määrin), koska sillä on pääsy kuoren sisäosiin.

Alkuperäinen komento type kärsi samanlaisesta ongelmasta kuin komentosarja which, koska se ei palauttanut vikatilanteen tilaa, jos komentoa ei löytynyt. Toisin kuin which, suoritettaville tiedostoille se antaa jotain ls is /bin/ls -tyyppistä pelkän mikä helpotti sen käyttöä komentosarjoissa.

Unix-version 8″ (ei julkaistu luonnossa) Bourne-kuoressa oli ”s type sisäänrakennettu uudelleen nimeksi whatis. Ja Plan9 (Unixin kerran tuleva seuraaja) kuori rc (ja sen johdannaisilla kuten akanga ja es) on myös whatis.

Korn-kuori (jonka osajoukko 80-luvun puolivälissä kehitetty POSIX sh -määritys perustuu), joka ei ollut laajalti saatavilla ennen vuotta 1988, ja lisäsi monia csh -ominaisuuksia ( rivieditori, aliakset …) Bourne-kuoren päällä. Se lisäsi oman whence sisäänrakennetun (lisäksi type), joka otti useita vaihtoehtoja (-v toimittaa type -tyyppisen sanatulostuksen ja -p etsimään vain suoritettavia tiedostoja (ei aliaksia / toimintoja …)) .

Samanaikaisesti AT & T: n ja Berkeleyn välisten tekijänoikeuskysymysten kanssa vallitsevaan myllerrykseen tuli muutama ilmainen ohjelmisto -kuoren toteutus. 80-luvun lopulla 90-luvun alussa.Kaikki Almquist-kuori (ash, joka korvaa Bourne-kuoren BSD-tiedostoissa), ksh (pdksh), bash (FSF: n sponsoroima), zsh ilmestyi vuoden 1989 ja 1991.

Vaikka Ash oli tarkoitettu korvaamaan Bourne-kuori, sillä ei ollut type -rakennetta vasta paljon myöhemmin (NetBSD 1.3: ssa ja FreeBSD 2.3: ssa). ), vaikka sillä oli hash -v. OSF / 1 /bin/sh: ssä oli sisäänrakennettu type joka palautti 0 OSF / 1 v3.x: ään. bash ei lisännyt whence, mutta lisäsi -p vaihtoehto type polun tulostamiseksi (type -p olisi kuin whence -p) ja -a raportoidaksesi kaikki vastaavat komennot. tcsh teki which sisäisen ja lisäsi where -komennon, joka toimii kuten bash” s type -a. zsh on ne kaikki.

fish shell (2005) -komennolla type on toiminto.

which csh-skripti poistettiin sillä välin NetBSD: ltä (koska se oli sisäänrakennettu tcsh: ssä eikä siitä ole paljon hyötyä muissa kuoreissa), ja toiminto lisättiin osioon whereis (kutsutaan nimellä which, whereis käyttäytyy kuten which, paitsi että se etsii vain suoritettavia tiedostoja ryhmästä iv id = ”00879d7bee” OpenBSD: ssä ja FreeBSD: ssä myös which muutettiin C-kirjaimeksi, joka etsii komentoja vain $PATH .

Toteutukset

which co: n toteutuksia on kymmeniä mmand useilla Unice-laitteilla, joilla on erilainen syntaksi ja käyttäytyminen.

Linuxissa (sisäänrakennettujen lisäksi tcsh ja zsh ) löydämme useita toteutuksia. Esimerkiksi viimeaikaisissa Debian-järjestelmissä se on yksinkertainen POSIX-komentotulkkikomento, joka etsii komentoja $PATH.

busybox: lla on myös which -komento.

On olemassa GNU which, joka on luultavasti kaikkein ylellisin. Se yrittää laajentaa which csh -skriptin tekoa muille kuoreille: voit kertoa sille, mitkä ovat aliaksesi ja toimintosi, jotta se voi antaa sinulle parempi vastaus (ja uskon, että jotkut Linux-jakelut asettavat sen ympärille joitain globaaleja aliaksia bash varten).

zsh: llä on pari operaattoria laajennettavaksi suoritettavien tiedostojen polulle: = tiedostonimen laajennus ja :c historialaajennuksen muokkaus (käytetään tässä parametrilaajennukseen ):

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

zsh, -moduuli tekee myös komennon hajautustaulukon commands -yhdistelmäryhmänä:

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

whatis -apuohjelma (paitsi Unix V8 Bourne -kuoressa tai Suunnitelma 9 rc / es) ei todellakaan ole yhteydessä toisiinsa, koska se on tarkoitettu vain dokumentaatioon (tarttuu whatis-tietokantaan, ts. man-sivun yhteenvetoon).

whereis oli myös lisätty tiedostoon 3BSD samaan aikaan kuin which, vaikka se kirjoitettiin C, ei csh ja sitä käytetään etsimään samanaikaisesti suoritettavaa tiedostoa, man-sivua ja lähdettä, mutta se ei perustu nykyiseen ympäristöön. Joten jälleen, tämä vastaa toiseen tarpeeseen.

Nyt POSIX määrittää vakiopuolella command -v ja -V -komennot (jotka olivat aiemmin valinnaisia POSIX.2008 asti). UNIX määrittää type -komennon (ei vaihtoehtoa). Että kaikkia (where, which, whence ei määritetä missään standardissa) .

Joitakin versioita saakka type ja command -v olivat valinnaisia Linux Standard Base -määrityksessä, mikä selittää miksi esimerkiksi joillakin posh -versioilla (vaikka ne perustuivatkin pdksh -ohjelmaan, joissa molemmat olivat) ei ollut kumpaakaan. command -v lisättiin myös joihinkin Bourne-shell-toteutuksiin (kuten Solarisissa).

Tila tänään

Nykyään tila on, että type ja command -v ovat läsnä kaikkialla Bournen kaltaiset kuoret (huomaa kuitenkin, kuten @jarno huomautti, huomautus / virhe kohdasta bash, kun et ole POSIX-tilassa, tai joitain Almquist-kuoren jälkeläisiä alla olevissa kommenteissa) tcsh on ainoa kuori, jossa haluat käyttää which (koska ei ole type siellä ja which on sisäänrakennettu).

Muissa kuoreissa kuin tcsh ja zsh, which saattaa kertoa sinulle annetun suoritettavan tiedoston polun, kunhan missään ~/.cshrc, ~/.bashrc tai mitä tahansa komentotulkin käynnistystiedostoa, etkä määritä $PATH ~/.cshrc. Jos sinulla on määritetty alias tai toiminto, se saattaa kertoa sinulle tai olla kertomatta sinulle tai kertoa väärän asian.

Jos haluat tietää Kaikista tietyn nimen komennoista ei ole mitään kannettavaa. Käytä where ryhmässä tcsh tai zsh, type -a bash tai zsh, whence -a muodossa ksh93 ja muissa kuoreissa , voit käyttää type yhdessä which -a: n kanssa, mikä saattaa toimia.

Suositukset

Polunimen saaminen suoritettavaan tiedostoon

Saadaksesi suoritettavan tiedoston polun komentosarjaan, on olemassa muutamia varoituksia:

ls=$(command -v ls) 

olisi tavanomainen tapa tehdä se.

On kuitenkin muutama ongelma:

  • Suoritettavan tiedoston polkua ei voida tietää suorittamatta sitä. type, which, command -v … kaikki käyttävät heuristiikkaa polun selvittämiseen He etenevät $PATH -komponenttien läpi ja löytävät ensimmäisen hakemistotiedoston, jolle sinulla on käyttöoikeus. Kun komento suoritetaan kuoressa, monet heistä (Bourne, AT & T ksh, zsh, ash …) vain suorittavat ne järjestyksessä $PATH kunnes execve -järjestelmäkutsu ei palaa virheellä. Esimerkiksi jos $PATH sisältää /foo:/bar ja haluat suorittaa ls, he yrittävät ensin suorittaa /foo/ls tai jos se epäonnistuu /bar/ls. /foo/ls -sovelluksen suoritus voi nyt epäonnistua, koska sinulla ei ole suorituslupaa, mutta myös monista muista syistä, kuten se ei ole kelvollinen suoritettava tiedosto. command -v ls raportoi /foo/ls, jos sinulla on suorituslupa kohteelle /foo/ls, mutta käynnissä ls saattaa todella suorittaa /bar/ls, jos /foo/ls ei ole kelvollinen suoritettava tiedosto.
  • jos foo on sisäänrakennettu tai funktio tai alias, command -v foo palauttaa foo. Joillakin kuorilla, kuten ash, pdksh tai zsh, se voi myös palauttaa foo jos $PATH sisältää tyhjän merkkijonon ja nykyisessä hakemistossa on suoritettava foo -tiedosto. Joissakin olosuhteissa sinun on ehkä otettava tämä huomioon. Pidä mielessä, että sisäänrakennettujen luettelo vaihtelee kuoren toteutuksen mukaan (esimerkiksi mount on joskus sisäänrakennettu busyboxille sh), ja esimerkiksi bash voi saada toimintoja ympäristöstä.
  • jos $PATH sisältää suhteelliset polkukomponentit (tyypillisesti . tai tyhjä merkkijono, jotka molemmat viittaavat nykyiseen hakemistoon, mutta voivat olla mitä tahansa) kuoresta riippuen, command -v cmd ei välttämättä tuota absoluuttista polkua. Joten polku, jonka hankit ajaessasi ei ole enää voimassa, kun olet cd jossakin muualla.
  • Anekdootti: ksh93-kuoren kanssa, jos /opt/ast/bin (tosin tarkka polku voi vaihdella eri järjestelmissä, joiden uskon olevan) on sinussa $PATH, ksh93 asettaa saataville muutaman ylimääräisen sisäänrakennetun version (chmod, cmp, cat …), mutta command -v chmod palauttaa /opt/ast/bin/chmod, vaikka polkua ei olisikaan.

Komennon olemassaolon selvittäminen

Voit selvittää tietyn komennon olemassaolon seuraavasti:

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

Missä voidaan käyttää which

(t)csh

Kohteissa csh ja tcsh sinulla ei ole paljon valinnanvaraa. Kohdassa tcsh ”hieno, kun which on sisäänrakennettu. Kohdassa csh se on järjestelmä which -komento, joka ei välttämättä tee haluamaasi joissakin tapauksissa.

Etsi komentoja vain joistakin simpukoista

Tapaus, jossa which on järkevää käyttää, on, jos haluat tietää komennon polun jättämättä potentiaalia sisäiset shell-toiminnot tai toiminnot bash, csh (ei tcsh), dash tai Bourne shell-komentosarjat, eli kuoret, joilla ei ole whence -p (kuten ksh tai zsh), command -ev (kuten yash ), whatis -p (rc, akanga) tai sisäänrakennettu which (kuten tcsh tai zsh) järjestelmissä, joissa which on käytettävissä, eikä se ole csh -skripti.

Jos nämä ehdot täyttyvät, niin:

echo=$(which echo) 

saat ensimmäisen echo ryhmässä $PATH (paitsi kulmatapauksissa) riippumatta siitä, onko echo myös kuori sisäänrakennettu / alias / function tai ei.

Muissa kuorissa haluat:

  • zsh : echo==echo tai echo=$commands[echo] tai echo=${${:-echo}:c}
  • ksh , zsh : echo=$(whence -p echo)
  • yash : echo=$(command -ev echo)
  • rc , akanga : echo=`whatis -p echo` (varo välilyöntejä sisältäviä polkuja)
  • kala : set echo (type -fp echo)

Huomaa, että jos haluat vain suorittaa että echo -komento, sinun ei tarvitse saada sen polkua, voit tehdä vain:

env echo this is not echoed by the builtin echo 

Esimerkiksi: tcsh, estämään sisäänrakennetun which: n käyttöä:

set Echo = "`env which echo`" 

Kun tarvitset ulkoista komentoa

Toinen tapaus, jossa haluat ehkä käyttää which, on, kun todella tarvitset tarvetta ulkoinen komento. POSIX edellyttää, että kaikki kuoren sisäänrakennetut sisäosat (kuten command) ovat saatavilla myös ulkoisina komentoina, mutta valitettavasti näin ei ole command monissa järjestelmissä. Esimerkiksi command -komento löytyy harvoin Linux-pohjaisista käyttöjärjestelmistä, kun taas useimmilla niistä on which -komento (tosin erilaisia, joilla on eri vaihtoehdot ja käyttäytymismallit).

Tapaukset, joissa haluat ehkä ulkoisen komennon, ovat missä tahansa, missä suoritat komennon kutsumatta POSIX-komentotulkkia.

system("some command line"), popen() … C: n tai useiden eri kielten toiminnot kutsuvat kuoren jäsentämään komentoriviä, joten system("command -v my-cmd") tehdä työtä niissä. Poikkeus tästä olisi perl, joka optimoi kuoren, jos se ei näe mitään shell-erikoismerkkiä (muuta kuin välilyönti). Tämä pätee myös sen backtick-operaattoriin:

$ 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 

Yllä olevan :; lisääminen pakottaa perl kutsumaan kuoren Käyttämällä which, sinun ei tarvitse käyttää tätä temppua.

Kommentit

  • @Joe, which on csh -skripti monissa kaupallisissa yksiköissä. Syy on historiallinen, että ’ miksi annoin historian, jotta ihmiset ymmärtäisivät, mistä se tuli, miksi ihmiset tottuivat siihen ja miksi itse asiassa siellä ’ ei ole mitään syytä sinun pitäisi käyttää sitä. Ja kyllä, jotkut ihmiset käyttävät (t) csh: tä. Kaikki eivät vielä käytä Linuxia.
  • Tämän viestin lukemisen jälkeen olen löytänyt paljon kontekstia vastaukselle, mutta en itse vastausta.Missä tässä viestissä todellakin sanotaan, miksi ei käytä which, toisin kuin asiat, joita yrität käyttää which tehtävä, which -historia, which -toteutukset, muut komennot liittyvien tehtävien suorittamiseen tai syyt tosiasialliseen käyttöön which? Miksi muut komennot ovat parempia ? Mitä he tekevät eri tavalla kuin which? Kuinka he välttävät sen sudenkuopat? Tämä vastaus kuluttaa todellisuudessa enemmän sanoja vaihtoehtojen ongelmiin kuin which -ongelmiin.
  • command on kuvattu kirjoittanut POSIX.
  • @St é phaneChazelas Jos luot uuden tiedoston touch /usr/bin/mytestfile ja suoritan sen jälkeen command -v mytestfile, se antaa polun (kun taas which mytestfile ei).
  • @jarno, kyllä, sinä ’ on oikeassa. bash asettuu tiedostoon, jota ei voida suorittaa, jos se ’ ei löydä suoritettavaa tiedostoa, joten se ’ s ” OK ” (tosin käytännössä mieluummin command -v / type palauttaa virheen), koska se ’ on komento, jonka se yrittää suorittaa, kun suoritat mytestfile, mutta dash -käyttäytyminen on buginen, ikään kuin ’ sa ei voi suorittaa cmd ennen suoritettavaa, command -v palauttaa suorittamattoman, kun cmd suoritetaan suoritettava (väärä yksi on myös hajautettu). FreeBSD: llä sh (perustuu myös ash) on sama vika. zsh, yash, ksh, mksh, bash kuten sh ovat kunnossa.

Vastaa

Syyt miksi ei halua käyttää which on jo selitetty, mutta tässä on muutama esimerkki muutamasta järjestelmästä, jossa which todella epäonnistuu.

Bournen kaltaisissa kuorissa verrataan uudelleen which -lähtöä type (type koska se on sisäänrakennettu kuori, sen on tarkoitus olla perustotuus, koska se on kuori, joka kertoo meille, kuinka se käynnistää komennon).

Monet tapaukset ovat corner -tapauksia, mutta pidä mielessä, että which / type käytetään usein kulmatapauksissa (vastauksen löytämiseksi) odottamattomaan käyttäytymiseen, kuten: miksi komento käyttäytyy tuolla tavalla, kumpaakin kutsun? ).

Useimmat järjestelmät, useimmat Bourne-tyyppiset kuoret: toiminnot

Ilmeisin tapaus koskee funktioita:

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

Syynä on se, että which raportoi vain suoritettavista tiedostoista ja joskus aliaksista (vaikkakaan ei aina sinun kuoresi), ei funktioista.

GNU: n man -sivulla on rikki (koska unohdettiin lainata $@) esimerkki siitä, kuinka sitä voidaan käyttää myös toimintojen raportointiin, mutta kuten aliaksia, koska se ei toteuta kuoren syntaksin jäsentäjää, se hämmentyy helposti:

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

Useimmat järjestelmät, useimmat Bourne-tyyppiset kuoret: sisäänrakennetut

Toinen ilmeinen tapaus on sisäänrakennettuja tai avainsanoja, koska which ulkoisena komennona ei ole mitään keinoa tietää, mitkä sisäiset komentot shellilläsi ovat (ja jotkut kuoret, kuten zsh, bash tai ksh voi ladata sisäänrakennettuja tiedostoja dynaamisesti):

$ 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 

(tämä ei koske zsh, johon which on rakennettu)

Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 ja monet muut:

$ 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 

Tämä johtuu siitä, että useimmissa kaupallisissa yksiköissä which (kuten alkuperäisessä toteutuksessa) 3BSD: llä) on csh komentosarja, joka lukee ~/.cshrc. Alias, jonka se raportoi, on määritelty siellä riippumatta tällä hetkellä määrittämistäsi aliaksista ja siitä, mitä kuorta todella käytät.

HP / UX tai Tru64:

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

(Solaris- ja AIX-versiot ovat korjanneet ongelman tallentamalla $path ennen kuin luit ~/.cshrc ja palauttaa se ennen komentojen hakemista)

$ 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 

Tai:

$ 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 

(tietysti csh -komentosarjana et voi odottaa sen toimivan välilyöntejä sisältävillä argumenteilla …)

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

Kyseisessä järjestelmässä on koko järjestelmän määrittämä alias, joka kietoo GNU which -komennon.

Väärä tuotos johtuu siitä, että which lukee bash ”s alias mutta ei osaa jäsentää sitä oikein ja käyttää heuristiikkaa (yksi alias riviä kohti, etsii ensimmäisen löydetyn komennon |, , & …)

CentOSin pahin asia on se, että zsh on täysin hieno which sisäänrakennettu komento, mutta CentOS onnistui hajottamaan sen korvaamalla sen toimimattomalla aliaksella GNU which.

Debian 7.0, ksh93:

(tosin koskee useimpia järjestelmiä, joissa on useita kuoria)

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

Debianissa /bin/which on komentosarja /bin/sh. Minun tapauksessani sh on dash, mutta se on sama, kun se ”s bash.

Poistamaton PATH ei ole poistaa käytöstä PATH -haku, vaan tarkoittaa järjestelmän käyttämistä ”s oletuspolku , josta valitettavasti Debianissa kukaan ei ole samaa mieltä (dash ja bash on /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, zsh on /bin:/usr/bin:/usr/ucb:/usr/local/bin, ksh93 on /bin:/usr/bin, mksh on /usr/bin:/bin ($(getconf PATH)), execvp() (kuten kohdassa env) on :/bin:/usr/bin (kyllä, näyttää ensin nykyisen hakemiston!)) .

Siksi which menee väärin yllä, koska se käyttää dash ”oletus PATH joka poikkeaa ksh93 ”s

Se” ei ” parempi kuin GNU which, joka raportoi:

which: no which in ((null)) 

(mielenkiintoista on, että /usr/local/bin/which järjestelmässäni, joka on itse asiassa akanga -skripti, jonka mukana tuli akanga (rc kuorijohdannainen, jossa oletuksena PATH on /usr/ucb:/usr/bin:/bin:.)))

bash, mikä tahansa järjestelmä:

Yksi Chris viittaa vastauksessaan :

$ 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 

Myös soittamisen jälkeen hash manuaalisesti:

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

Nyt tapaus, jossa which ja joskus type epäonnistuu:

$ 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 

Nyt joillakin kuorilla:

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

Muiden kanssa:

$ foo a/foo 

Ei which eikä type voi tietää etukäteen, että b/foo ei voi b Suoritettu. Jotkut kuoret, kuten bash, ksh tai yash, kun kutsutaan foo yrittää todellakin suorittaa b/foo ja ilmoittaa virheestä, kun taas toiset (kuten zsh, ash, csh, Bourne, tcsh) suoritetaan a/foo execve() -järjestelmän kutsun epäonnistumisen yhteydessä b/foo.

Kommentit

  • mksh käyttää oletusarvoisesti jotakin erilaista $PATH: ensin , käyttöjärjestelmän käännösaikavakiota _PATH_DEFPATH käytetään (yleisimmin BSD-levyillä), sitten käytetään confstr(_CS_PATH, …) (POSIX), ja jos molempia ei ole tai ne epäonnistuvat, käytetään /bin:/usr/bin:/sbin:/usr/sbin.
  • Ensimmäisessä esimerkissä, vaikka ls on funktio, jota käytetään g ls polusta PATH. Ja which on hyvä kertoa, mitä niistä käytetään /usr/bin/ls tai /usr/local/bin/ls. En näe ’ en näe ” Miksi en käyttäisi sitä, mikä ” ….
  • @rudimeier, Se which ls antaa minulle /bin/ls riippumatta siitä, onko ls -funktiokutsut /bin/ls tai /opt/gnu/bin/ls tai dir tai ei mitään. IOW, which (mitä toteutukset, IMMV) antaa jotain merkityksetöntä
  • @St é phaneChazelas. Ei ei ei. tiedän jo, että ls on funktio. tiedän että ls -toimintoni kutsuu ls -kenttää osoitteesta PATH. Nyt which kertoo minulle, missä tiedosto on. Näet vain yhden kertakäyttöisen tapauksen: ” Mitä kuorini tekisi tällä komennolla. ” Tässä käyttötapauksessa which on väärä, oikea.Mutta on muitakin käyttötapauksia, joissa (GNU) which on täsmälleen oikea asia.
  • @rudimeter, riippuu which toteutus. Jotkut kertovat sinulle ’ s aliaksen (jos sinulla on määritetty alias tai jos kotonasi on ~/.cshrc kuten alias), jotkut antavat sinulle polun, mutta väärän tietyissä olosuhteissa. sh -c 'command -v ls', vaikka se ei olekaan täydellinen, antaa sinulle todennäköisesti oikean vastauksen erilaisiin vaatimuksiin (ja on myös vakio).

Vastaa

Yksi asia, josta (pikakäynnistyksestäni) näyttää siltä, että Stephane ei maininnut, on se, että which on ei ole aavistustakaan shellisi polun hash-taulukosta. Tällä on vaikutusta siihen, että se saattaa palauttaa tuloksen, joka ei edusta suoritettua, mikä tekee siitä tehottoman virheenkorjauksessa.

Vastaa

Ripustan yleensä, kun tätä kysymystä suositellaan epäuskoisille käyttäjille, koska perusteeton which -tukeminen ei ole hyödyllistä kenellekään.

Jos which toimii hyvin ja antaa oikean vastauksen joihinkin tehtäviin Unix-moton mukaisesti: tee yksi asia, tee se hyvin , miksi which olla kielletty?

Kysymyksen pitäisi siis olla, mikä toimii hyvin ja tekee tietyn työn hyvin?

Yhdelle ulkoinen apuohjelma osoitteessa / bin / joka Debianissa on shell-komentosarja, jonka tavoitteena on vain luetella tietyn nimen suoritettavat tiedostot polulle. Uskon, että which tekee tarkoituksensa oikein. Se ei lataa mitään aliaksia, ei toimintoja, ei mitään komentotulkista, vaan vain listaa tietyn nimen ensimmäiset (tai kaikki) suoritettavat tiedostot PATH: iin. mikä tarkoittaa , että käyttäjä on löytänyt saman nimisen tiedoston, on käyttäjän (hänen) selvitettävä asia itse.

Kyllä, muilla which toteutuksilla voi olla (ja yleensä onkin) tiettyjä ongelmia.

Vastaa

Kuulemme usein sitä, jota tulisi välttää. Miksi? Mitä meidän pitäisi käyttää sen sijaan?

En ole koskaan kuullut sitä. Anna tarkkoja esimerkkejä. Olen huolissani Linux-jakelustasi ja asennetuista ohjelmistopaketeistasi, koska sieltä which tulee!

SLES 11.4 x86-64

tcsh-versiossa 6.18.01:

> which which which: shell built-in command. 

bash-versiossa 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 on osa util-linux vakiopaketti, jonka Linux Kernel Organization jakelee käytettäväksi osana Linux-käyttöjärjestelmää. Se tarjoaa myös nämä muut tiedostot

/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 

minun util-linux on versio 2.19. Julkaisutiedot löytyvät helposti v2.13: sta (päivätty 28. elokuuta 2007). Etkö ole varma, mikä tämän päämäärä tai tavoite oli, siihen ei varmasti vastattu tuossa pidenneessä äänessä 331 kertaa.

Kommentit

  • Huomaa, kuinka kysymyksessä ei mainita, mihin Unixiin se viittaa. Linux on vain yksi harvoista.
  • Kuten which -v osoittaa, että ’ on GNU, joka (ylimääräinen) toinen mainitaan toisessa vastauksessa eikä se ole mitenkään spesifinen Linuxille), ei util-linux, johon AFAIK ei koskaan sisällyttänyt which -apuohjelmaa. util-linux 2.19 on vuodelta 2011, GNU, joka 2.19 on vuodelta 2008.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *