Hvorfor ikke bruge “ hvilken ”? Hvad skal jeg så bruge?

Når du leder efter stien til en eksekverbar eller kontrollerer, hvad der ville ske, hvis du indtaster et kommandonavn i en Unix-shell, er der en overflod af forskellige hjælpeprogrammer ( which, type, command, whence, where, whereis, whatis, hash osv.).

Vi hører ofte, at which bør undgås. Hvorfor? Hvad skal vi bruge i stedet?

Kommentarer

  • Jeg tror, at de fleste argumenter mod at bruge which antager en interaktiv shell-kontekst. Dette spørgsmål er tagget / bærbarhed. Så jeg fortolker spørgsmålet i denne sammenhæng som ” hvad man skal bruge i stedet for which til at finde den første eksekverbare fil af et givet navn i $PATH “. De fleste svar og grunde imod which beskæftiger sig med aliaser, indbyggede funktioner og funktioner, som i de fleste bærbare shell-scripts fra den virkelige verden bare er af akademisk interesse. Lokalt definerede aliasser arves ikke ‘ t, når du kører et shell-script (medmindre du kilder det til .).
  • @MattBianco, ja, csh (og which er stadig et csh script på de fleste kommercielle Unices) læser ~/.cshrc når de ikke er interaktive. At ‘ hvorfor du ‘ bemærker, at csh-scripts normalt starter med #! /bin/csh -f. which ikke fordi det sigter at give dig aliaserne, fordi det ‘ er ment som et værktøj til (interaktive) brugere af csh. Brugere af POSIX-skaller har command -v.
  • @rudimeier, så er svaret altid, medmindre din shell er (t)csh (eller hvis du ikke ‘ ikke har noget imod det, hvis det ikke ‘ ikke giver dig det rigtige resultat), brug type eller command -v i stedet . Se svarene til hvorfor .
  • @rudimeier, (stat $(which ls) er forkert af flere årsager (mangler --, manglende anførselstegn), ikke kun brugen af which). Du ‘ bruger stat -- "$(command -v ls)". Det antager, at ls faktisk er en kommando, der findes på filsystemet (ikke en indbygget i din shell eller aliasfunktion). which kan give dig den forkerte sti (ikke den sti, som din shell ville udføre, hvis du indtastede ls) eller give dig et alias som defineret i konfigurationen af nogle andre skaller …
  • @rudimeier, igen, der er en række betingelser, under hvilke mange which implementeringer ikke ville give dig engang ls der ville blive fundet ved et opslag af $PATH (uanset hvad ls kan påberåbe sig i din skal). sh -c 'command -v ls' eller zsh -c 'rpm -q --whatprovides =ls' er mere tilbøjelige til at give dig det rigtige svar. Pointen her er, at which er en brudt arv fra csh.

Svar

Her er alt, hvad du aldrig troede, du aldrig ville have lyst til at vide om det:

Oversigt

For at få stienavn på en eksekverbar i et Bourne-lignende shell-script (der er et par advarsler; se nedenfor):

ls=$(command -v ls) 

For at finde ud af om der findes en given kommando:

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

Ved prompt af en interaktiv Bourne-lignende shell:

type ls 

The which -kommandoen er en ødelagt arv fra C-Shell og er bedre alene i Bourne-lignende skaller.

Brug sager

Der “en sondring mellem at kigge efter disse oplysninger som en del af et script eller interaktivt på shellprompten.

Ved shellprompten er den typiske brugssag: denne kommando opfører sig underligt, bruger jeg rigtig? Hvad skete der nøjagtigt, da jeg skrev mycmd? Kan jeg se nærmere på, hvad det er?

I så fald vil du vide, hvad din shell gør, når du påberåber sig kommandoen uden faktisk at påberåbe sig kommandoen.

I shell-scripts har det en tendens til at være helt anderledes. I et shell-script er der ingen grund til, at du vil vide, hvor eller hvad en kommando er, hvis alt hvad du vil gøre er at køre den. Generelt er det, du vil vide, stien til den eksekverbare, så du kan få mere information ud af den (som stien til en anden fil i forhold til den, eller læse oplysninger fra indholdet af den eksekverbare fil på den sti).

Interaktivt vil du måske vide om alle my-cmd kommandoer, der er tilgængelige på systemet, i scripts, sjældent.

De fleste af de tilgængelige værktøjer (som det ofte er tilfældet) er designet til at blive brugt interaktivt.

Historie

Først en smule historie.

De tidlige Unix-skaller indtil slutningen af 70erne havde ingen funktioner eller aliaser. Kun den traditionelle sletning af eksekverbare filer i $PATH. csh introducerede alias omkring 1978 (skønt csh først blev frigivet i 2BSD, i maj 1979), og også behandlingen af en .cshrc for brugerne til at tilpasse shell (hver shell, som csh , læser .cshrc selv når det ikke er interaktivt som i scripts).

Mens Bourne-skallen først blev frigivet i Unix V7 tidligere i 1979, blev funktionssupport kun tilføjet meget senere (1984 i SVR2), og alligevel havde den aldrig noget rc fil (.profile er til at konfigurere dit miljø, ikke skallen per se ).

csh blev meget mere populær end Bourne-skallen, da (selvom den havde en frygtelig dårligere syntaks end Bourne shell) tilføjede en masse mere praktiske og pæne funktioner til interaktiv brug.

I 3BSD (1980), en which csh-script blev tilføjet til csh -brugerne for at hjælpe med at identificere en eksekverbar, og det er et næppe andet script, du kan finde som which på mange kommercielle enheder i dag (som Solaris, HP / UX, AIX eller Tru64).

Dette script læser brugeren” s ~/.cshrc (som alle csh scripts gør, medmindre de påkaldes med csh -f) og ser de angivne kommandonavne op på listen over aliasser og i $path (det array, som csh opretholder baseret på $PATH).

Here you go: which kom først efter den mest populære shell på det tidspunkt (og csh var stadig populær indtil midten af 90erne), hvilket er hovedårsagen til, at det blev dokumenteret i bøger og stadig bruges i vid udstrækning.

Bemærk, at selv for en csh -bruger, at which csh-script giver dig ikke nødvendigvis de rigtige oplysninger. Det får de aliasser, der er defineret i ~/.cshrc, ikke dem, du måske har defineret senere ved prompten eller for eksempel ved source ved en anden csh fil, og (selvom det ikke ville være en god idé), kan PATH muligvis omdefineres i ~/.cshrc.

At køre den which -kommando fra en Bourne-shell vil stadig slå aliasser op, der er defineret i din ~/.cshrc hvis du ikke har en, fordi du ikke bruger csh, ville det sandsynligvis stadig give dig det rigtige svar.

En lignende funktionalitet blev ikke tilføjet til Bourne-skallen indtil 1984 i SVR2 med type indbygget kommando. Det faktum, at det er indbygget (i modsætning til et eksternt script) betyder, at det kan give dig de rigtige oplysninger (til en vis grad), da det har adgang til skallenes indre.

Den oprindelige type kommando led af et lignende problem som which scriptet, idet det ikke returnerede en status for fejlafslutning, hvis kommandoen blev ikke fundet. For eksekverbare filer, i modsætning til which, udsender den noget som ls is /bin/ls i stedet for bare /bin/ls hvilket gjorde det mindre let at bruge i scripts.

Unix version 8″ s (ikke frigivet i naturen) Bourne-shell havde det “s type indbygget omdøbt til whatis. Og Plan9 (en gang efterfølger til Unix) skal rc (og dens derivater som akanga og es) har også whatis.

Korn-skallen (en delmængde, hvoraf POSIX sh definition er baseret på), udviklet i midten af 80erne, men ikke bredt tilgængelig før 1988, tilføjede mange af csh -funktionerne ( line editor, aliaser …) oven på Bourne shell. Det tilføjede sin egen whence builtin (ud over type), som tog flere muligheder (-v for at give type -lignende verbose output og -p for kun at se efter eksekverbare filer (ikke aliaser / funktioner …)) .

Tilfældig med uroen med hensyn til ophavsretsspørgsmål mellem AT & T og Berkeley, kom der et par gratis software shellimplementeringer ud i slutningen af 80erne begyndelsen af 90erne.Hele Almquist-skallen (ash, som erstatning for Bourne-skallen i BSDer), implementeringen af det offentlige domæne af ksh (pdksh), bash (sponsoreret af FSF), zsh kom ud mellem 1989 og 1991.

Ash, selvom det var meningen at være en erstatning for Bourne-skallen, havde ikke en type indbygget indtil meget senere (i NetBSD 1.3 og FreeBSD 2.3 ), selvom det havde hash -v. OSF / 1 /bin/sh havde en type som altid returnerede 0 op til OSF / 1 v3.x. bash tilføjede ikke en whence men tilføjede en -p mulighed for at type for at udskrive stien (type -p ville være som whence -p) og -a for at rapportere alle de matchende kommandoer. tcsh lavede which indbygget og tilføjede en where kommando, der fungerer som bash” s type -a. zsh har dem alle.

fish shell (2005) har en type -kommando implementeret som en funktion.

which csh-script blev i mellemtiden fjernet fra NetBSD (da det var indbygget i tcsh og ikke meget brug i andre skaller), og funktionaliteten blev føjet til whereis (når påkaldt som which, whereis opfører sig som which bortset fra at den kun ser på eksekverbare filer i iv id = “00879d7bee” I OpenBSD og FreeBSD blev which også ændret til en skrevet i C, der kun ser kommandoer i $PATH .

Implementeringer

Der er snesevis af implementeringer af en which co mmog på forskellige enheder med forskellig syntaks og adfærd.

På Linux (ved siden af de indbyggede i tcsh og zsh ) vi finder flere implementeringer. På for nylig Debian-systemer er det “et simpelt POSIX-shell-script, der ser efter kommandoer i $PATH.

busybox har også en which kommando.

Der er en GNU which som sandsynligvis er den mest ekstravagante. Den forsøger at udvide, hvad which csh-scriptet gjorde til andre skaller: du kan fortælle det, hvad dine aliaser og funktioner er, så det kan give dig et bedre svar (og jeg tror, at nogle Linux-distributioner angiver nogle globale aliaser omkring det for bash for at gøre det).

zsh har et par operatorer til at udvide til stien til eksekverbare filer: operatøren = filnavnudvidelse og :c historieudvidelsesmodifikator (her anvendt på parameterudvidelse ):

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

zsh, i -modul gør også kommandot hash-tabellen som commands associativ matrix:

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

whatis -værktøjet (undtagen den i Unix V8 Bourne-skal eller Plan 9 rc / es) er ikke rigtig relateret, da det kun er til dokumentation (greps whatis-databasen, det vil sige manopsidens “).

whereis var også tilføjet i 3BSD på samme tid som which selvom det blev skrevet i C, ikke csh og bruges til at slå op på samme tid, den eksekverbare, man-side og kilde, men ikke baseret på det aktuelle miljø. Så igen svarer det på et andet behov.

Nu på standardfronten specificerer POSIX command -v og -V kommandoer (som tidligere var valgfri indtil POSIX.2008). UNIX angiver kommandoen type (ingen mulighed). At “s alle (where, which, whence er ikke angivet i nogen standard) .

Op til en eller anden version var type og command -v valgfri i Linux Standard Base-specifikationen, hvilket forklarer hvorfor nogle gamle versioner af posh (dog baseret på pdksh, som begge havde begge), havde heller ikke nogen. command -v blev også føjet til nogle Bourne shell-implementeringer (som på Solaris).

Status i dag

Status i dag er, at type og command -v er allestedsnærværende de Bourne-lignende skaller (dog som bemærket af @jarno skal du bemærke advarslen / bugten i bash når de ikke er i POSIX-tilstand eller nogle efterkommere af Almquist-skallen nedenfor i kommentarer). tcsh er den eneste skal, hvor du vil bruge which (da der ikke er noget type der og which er indbygget).

I andre skaller end tcsh og zsh, which fortæller dig muligvis stien til den givne eksekverbare, så længe der ikke er noget alias eller funktion med det samme navn i nogen af vores ~/.cshrc, ~/.bashrc eller en hvilken som helst shell-startfil, og du definerer ikke $PATH i din ~/.cshrc. Hvis du har defineret et alias eller en funktion til det, fortæller det dig måske ikke eller fortæller dig den forkerte ting.

Hvis du vil vide det om alle kommandoerne med et givet navn er der intet bærbart. Du ville bruge where i tcsh eller zsh, type -a i bash eller zsh, whence -a i ksh93 og i andre skaller , kan du bruge type i kombination med which -a som muligvis fungerer.

Anbefalinger

At få stienavnet til en eksekverbar

For at få stienavnet til en eksekverbar i et script er der et par advarsler:

ls=$(command -v ls) 

ville være den standard måde at gøre det på.

Der er dog nogle få problemer:

  • Det er ikke muligt at kende stien til den eksekverbare uden at udføre den. type, which, command -v … alle bruger heuristik til at finde ud af stien De løber gennem $PATH -komponenterne og finder den første ikke-biblioteksfil, som du har tilladelse til. Dog depe nding på skallen, når det kommer til udførelse af kommandoen, vil mange af dem (Bourne, AT & T ksh, zsh, ash …) bare udføre dem i rækkefølgen af $PATH indtil execve systemopkald vender ikke tilbage med en fejl. For eksempel, hvis $PATH indeholder /foo:/bar, og du vil udføre ls, prøver de først at udføre /foo/ls eller hvis det mislykkes /bar/ls. Nu kan udførelse af /foo/ls muligvis mislykkes, fordi du ikke har eksekveringstilladelse, men også af mange andre grunde, da det ikke er en gyldig eksekverbar. command -v ls rapporterer /foo/ls hvis du har eksekveringstilladelse til /foo/ls, men kører ls kører muligvis /bar/ls hvis /foo/ls ikke er en gyldig eksekverbar fil.
  • hvis foo er en indbygget funktion eller et alias, returnerer command -v foo foo. Med nogle skaller som ash, pdksh eller zsh, kan det også returnere foo hvis $PATH inkluderer den tomme streng, og der er en eksekverbar foo -fil i den aktuelle mappe. Der er nogle omstændigheder, hvor du muligvis skal tage det i betragtning. Husk for eksempel, at listen over indbyggede varierer med implementeringen af shell (for eksempel er mount undertiden indbygget til optaget boks sh), og f.eks. bash kan få funktioner fra miljøet.
  • hvis $PATH indeholder relative stykomponenter (typisk . eller den tomme streng, som begge henviser til den aktuelle mappe, men som muligvis kan være hvad som helst), afhængigt af skallen, command -v cmd udsender muligvis ikke en absolut sti. Så den sti, du opnår på det tidspunkt, du kører er ikke længere gyldig, efter at du cd et andet sted.
  • Anekdotisk: med ksh93-skallen, hvis /opt/ast/bin (selvom den nøjagtige sti kan variere på forskellige systemer, tror jeg) er i dig $PATH, ksh93 vil stille et par ekstra indbyggede til rådighed (chmod, cmp, cat …), men command -v chmod returnerer /opt/ast/bin/chmod, selvom stien ikke findes.

Bestemmelse af, om der findes en kommando

For at finde ud af, om en given kommando eksisterer som standard, kan du gøre:

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

Hvor man måske vil bruge which

(t)csh

I csh og tcsh har du ikke meget valg. I tcsh er det “s fint som which er indbygget. I csh er det kommandoen which, som muligvis ikke gør hvad du vil i nogle få tilfælde.

Find kun kommandoer i nogle skaller

Et tilfælde, hvor det kan være fornuftigt at bruge which er, hvis du vil kende stien til en kommando og ignorere potentialet shell-indbyggede funktioner i bash, csh (ikke tcsh), dash eller Bourne shell-scripts, det vil sige skaller, der ikke har whence -p = “cd104fd905”>

ellerzsh),command -ev(somyash),whatis -p(rc,akanga) eller en indbyggetwhich(somtcshellerzsh) på systemer, hvorwhichtilgængelig og er ikkecshscript.

Hvis disse betingelser er opfyldt, vil:

echo=$(which echo) 

give dig stien til den første echo i $PATH (undtagen i hjørnetilfælde), uanset om echo også tilfældigvis er en shell indbygget / alias / funktion eller ej.

I andre skaller foretrækker du:

  • zsh : echo==echo eller echo=$commands[echo] eller echo=${${:-echo}:c}
  • ksh , zsh : echo=$(whence -p echo)
  • yash : echo=$(command -ev echo)
  • rc , akanga : echo=`whatis -p echo` (pas på stier med mellemrum)
  • fisk : set echo (type -fp echo)

Bemærk, at hvis alt hvad du vil gøre er kør at echo kommando, du behøver ikke at få sin sti, du kan bare gøre:

env echo this is not echoed by the builtin echo 

For eksempel med tcsh for at forhindre, at det indbyggede which bruges:

set Echo = "`env which echo`" 

Når du har brug for en ekstern kommando

Et andet tilfælde, hvor du måske vil bruge which, er når du faktisk har brug for en ekstern kommando. POSIX kræver, at alle shell-indbyggede (som command) også er tilgængelige som eksterne kommandoer, men desværre er det ikke tilfældet for command på mange systemer. For eksempel er det sjældent at finde en command kommando på Linux-baserede operativsystemer, mens de fleste af dem har en which kommando (dog forskellige med forskellige indstillinger og adfærd).

Tilfælde, hvor du muligvis vil have en ekstern kommando, vil være overalt, hvor du udfører en kommando uden at påkalde en POSIX-shell.

system("some command line"), popen() … funktioner på C eller forskellige sprog påkalder en shell for at analysere kommandolinjen, så system("command -v my-cmd") arbejder i dem. En undtagelse derfra ville være perl, som optimerer skallen, hvis den ikke ser noget shell-specialtegn (bortset fra mellemrum). Det gælder også dens backtick-operatør:

$ 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 

Tilføjelsen af den :; ovenfor tvinger perl til at påkalde en shell der. Ved at bruge which behøver du ikke bruge det trick.

Kommentarer

  • @Joe, which er et csh script på mange kommercielle enheder. Årsagen er historisk, at ‘ hvorfor jeg gav historien, så folk forstår, hvor den kom fra, hvorfor folk blev vant til at bruge den, og hvorfor der faktisk ‘ er ingen grund til at bruge det. Og ja, nogle mennesker bruger (t) csh. Ikke alle bruger Linux endnu
  • Efter at have læst dette indlæg har jeg fundet en masse kontekst til svaret, men ikke selve svaret.Hvor i dette indlæg siger det faktisk ikke at bruge which i modsætning til ting, du måske prøver at bruge which at gøre, historien om which, implementeringer af which, andre kommandoer til at udføre relaterede opgaver eller grunde til faktisk at bruge which? Hvorfor er de andre kommandoer bedre ? Hvad gør de anderledes end which? Hvordan undgår de faldgruber? Dette svar bruger faktisk flere ord på problemerne med alternativerne end problemerne med which.
  • command er beskrevet af POSIX.
  • @St é phaneChazelas Hvis jeg opretter en ny fil med touch /usr/bin/mytestfile og kør derefter command -v mytestfile, det giver stien (hvorimod which mytestfile ikke).
  • @jarno, åh ja, du ‘ har ret. bash vil slå sig ned på en ikke-eksekverbar fil, hvis den ‘ ikke kan finde en eksekverbar fil, så den ‘ s ” OK ” (selvom man i praksis hellere vil command -v / type returnerer en fejl) som at ‘ er kommandoen, den vil prøve at udføre, når du kører mytestfile, men dash adfærd er ujævn, som om der ‘ er en ikke-eksekverbar cmd foran en eksekverbar en command -v returnerer den ikke-eksekverbare, mens udførelse af cmd ville udføre den eksekverbare (den forkerte man er også hash). FreeBSD sh (også baseret på ash) har den samme fejl. zsh, yash, ksh, mksh, bash som sh er OK.

Svar

Årsagerne til, at man kan ikke ønsker at bruge which er allerede blevet forklaret, men her er et par eksempler på et par systemer, hvor which faktisk fejler.

På Bourne-lignende skaller sammenligner vi output fra which med output fra type (type er en shell-indbygget, menes det at være grundens sandhed, da det er skallen, der fortæller os, hvordan det vil påberåbe sig en kommando).

Mange tilfælde er hjørne sager, men husk at which / type ofte bruges i hjørnesager (for at finde svaret til en uventet opførsel som: hvorfor i alverden opfører den kommando sig sådan, hvilken kalder jeg på? ).

De fleste systemer, de fleste Bourne-lignende skaller: funktioner

Det mest oplagte tilfælde er for funktioner:

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

Årsagen er, at which kun rapporterer om eksekverbare filer og nogle gange om aliaser (dog ikke altid dem fra din shell), ikke om funktioner.

Den GNU, som man-siden har brudt (da de glemte at citere $@) eksempel på, hvordan man også bruger den til at rapportere funktioner, men ligesom for aliaser, fordi den ikke implementerer en shell-syntaks-parser, narre den let:

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

De fleste systemer, mest Bourne-lignende skaller: builtins

Et andet indlysende tilfælde er indbyggede eller nøgleord, da which at være en ekstern kommando ikke har nogen måde at vide, hvilke indbyggede din shell har (og nogle skaller som zsh, bash eller ksh kan indlæse buildins dynamisk):

$ 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 

(det gælder ikke for zsh hvor which er indbygget)

Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 og mange andre:

$ 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 

Dette skyldes, at de fleste kommercielle enheder which (som i den oprindelige implementering på 3BSD) er et csh script, der læser ~/.cshrc. De aliasser, den rapporterer, er dem, der er defineret der uanset de aliasser, du i øjeblikket har defineret, og uanset den shell, du rent faktisk bruger.

I HP / UX eller Tru64:

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

(Solaris- og AIX-versionerne har løst problemet ved at gemme $path før du læser ~/.cshrc og gendanne det, før du slår kommandoen (e) op)

$ 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 

Eller:

$ 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 

(selvfølgelig, da du er et csh script, kan du ikke forvente, at det fungerer med argumenter, der indeholder mellemrum …)

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

På dette system er der et alias-defineret system-bredt, der omslutter GNU which -kommandoen.

Den falske output skyldes, at which læser output fra bash “s alias men ved ikke, hvordan man analyserer det ordentligt og bruger heuristik (et alias pr. linje, ser efter den første fundne kommando efter en |, ;, & …)

Det værste ved CentOS er, at zsh har en perfekt fin which indbygget kommando, men CentOS formåede at bryde den ved at erstatte den med et ikke-fungerende alias til GNU which.

Debian 7.0, ksh93:

(dog gælder de fleste systemer med mange skaller)

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

På Debian, /bin/which er et /bin/sh script. I mit tilfælde er sh dash men det er det samme, når det “s bash.

En ikke-indstillet PATH er ikke til at deaktivere PATH opslag, men betyder at bruge systemet “s standard PATH som desværre på Debian ikke er enig i (dash og bash har /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, zsh har /bin:/usr/bin:/usr/ucb:/usr/local/bin, ksh93 har /bin:/usr/bin, mksh har /usr/bin:/bin ($(getconf PATH)), execvp() (som i env) har :/bin:/usr/bin (ja, ser først i den aktuelle mappe!)) .

Derfor får which det forkert ovenfor, da det bruger dash “s standard PATH som er forskellig fra ksh93 “s

Det er nej t bedre med GNU which som rapporterer:

which: no which in ((null)) 

(interessant er der faktisk en /usr/local/bin/which på mit system, som faktisk er et akanga script, der fulgte med akanga (et rc shell-derivat, hvor standard PATH er /usr/ucb:/usr/bin:/bin:.))

bash, ethvert system:

Den Chris henviser til i sit svar :

$ 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 

Også efter at have ringet til hash manuelt:

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

Nu er det tilfældet, hvor which og undertiden type mislykkes:

$ 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 

Nu med nogle skaller:

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

Med andre:

$ foo a/foo 

Hverken which eller type kan på forhånd vide, at b/foo ikke kan b e udført. Nogle skaller som bash, ksh eller yash, når de påkalder foo vil faktisk prøve at køre b/foo og rapportere en fejl, mens andre (som zsh, ash, csh, Bourne, tcsh) kører a/foo ved fejl i execve() systemkald b/foo.

Kommentarer

  • mksh bruger faktisk noget andet til standard $PATH: først , bruges operativsystemets kompileringstidskonstant _PATH_DEFPATH (oftest på BSDer), derefter anvendes confstr(_CS_PATH, …) (POSIX), og hvis begge ikke findes eller mislykkes, bruges /bin:/usr/bin:/sbin:/usr/sbin.
  • I dit 1. eksempel, selvom ls er en funktion, den bruges i g ls fra PATH. Og which er fint at fortælle dig, hvilken der bruges /usr/bin/ls eller /usr/local/bin/ls. Jeg ser ikke ‘ ” Hvorfor ikke bruge hvilken ” ….
  • @rudimeier, At which ls giver mig /bin/ls uanset om ls funktion kalder /bin/ls eller /opt/gnu/bin/ls eller dir eller slet ingenting. IOW, which (det, som implementeringer, IMMV) giver noget irrelevant
  • @St é phaneChazelas. Nej Nej Nej. Jeg ved allerede, at min ls er en funktion. Jeg ved at min ls funktion kalder ls fra PATH. Nu fortæller which mig, hvor filen er. Du ser kun en enkelt brugssag: ” Hvad ville min shell gøre med denne kommando. ” Til denne brugssag which er forkert, korrekt.Men der er andre brugstilfælde, hvor (GNU) which er nøjagtigt den rigtige ting.
  • @rudimeter afhænger af which implementering. Nogle vil fortælle dig, at det ‘ er et alias (hvis du har et alias konfigureret, eller hvis der er et ~/.cshrc i dit hjem, der har sådan et alias), nogle vil give dig en vej, men den forkerte under visse betingelser. sh -c 'command -v ls', selvom det ikke er perfekt, er det stadig mere sandsynligt, at det giver dig det rigtige svar på det forskellige krav (og er også standard).

Svar

En ting, som (fra mit hurtige skum) ser ud til, at Stephane ikke nævnte, er at which har ingen idé om din shell “sti-hash-tabel. Dette har den virkning, at det muligvis returnerer et resultat, der ikke er repræsentativt for det, der faktisk køres, hvilket gør det ineffektivt i fejlfinding.

Svar

Jeg krymper normalt, når dette spørgsmål anbefales til intetanende brugere, fordi grundløs bashing på which ikke er nyttig for nogen.

Hvis which fungerer godt og giver det rigtige svar på en eller anden opgave ved at følge Unix-motoen: gør en ting, gør det godt hvorfor skal which være forbudt?

Spørgsmålet skal så være, hvilken der fungerer godt og gør et specifikt job godt?

For det ene er det eksterne værktøj ved / bin / hvilket i Debian er et shell-script, hvis mål kun er at angive eksekverbare filer med det givne navn på stien. Jeg tror, at which gør sit tilsigtede mål korrekt. Den indlæser ingen aliaser, ingen funktioner, intet fra skallen, lister bare de første (eller alle) eksekverbare filer af det givne navn på PATH. betyder for at have fundet en fil med samme navn som givet er noget, som brugeren skal finde ud af af hende (ham) selv.

Ja, andre which implementeringer kan (og har normalt) særlige problemer.

Svar

Vi hører ofte, hvad der skal undgås. Hvorfor? Hvad skal vi bruge i stedet?

Det har jeg aldrig hørt. Angiv specifikke eksempler. Jeg ville bekymre mig om din linux-distribution og installerede softwarepakker, for det er det sted, hvor which kommer fra!

SLES 11.4 x86-64

i tcsh version 6.18.01:

> which which which: shell built-in command. 

i bash-version 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 er en del af util-linux en standardpakke distribueret af Linux Kernel Organization til brug som en del af Linux-operativsystemet. Det giver også disse andre filer

/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 

min util-linux er version 2.19. Udgivelsesnoter kan let findes tilbage til v2.13 dateret (28. august 2007). Ikke sikker på hvad pointen eller målet med dette var, det blev bestemt ikke besvaret i den lange ting, der blev opstemt 331 gange.

Kommentarer

  • Bemærk hvordan spørgsmål nævnes ikke, hvad Unix det henviser til. Linux er blot et af få.
  • Som din which -v viser, at ‘ s GNU som (det ekstravagante en nævnt i det andet svar og er på ingen måde specifik for Linux), ikke util-linux, som AFAIK aldrig inkluderede et which -værktøj. util-linux 2.19 er fra 2011, GNU som 2.19 er fra 2008.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *