Cuando busque la ruta a un ejecutable o verifique lo que sucedería si ingresa un nombre de comando en un shell de Unix, hay una plétora de utilidades diferentes ( which
, type
, command
, whence
, where
, whereis
, whatis
, hash
, etc.).
A menudo escuchamos que which
debe evitarse. ¿Por qué? ¿Qué deberíamos usar en su lugar?
Comentarios
Respuesta
Aquí está todo lo que nunca pensó que no querría saber al respecto:
Resumen
Para obtener el nombre de ruta de un ejecutable en un script de shell similar a Bourne (hay algunas advertencias; ver más abajo):
ls=$(command -v ls)
Para averiguar si existe un comando dado:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
En el indicador de un shell interactivo similar a Bourne:
type ls
El which
El comando es una herencia rota de C-Shell y es mejor dejarlo solo en shells tipo Bourne.
Casos de uso
Allí «una distinción entre buscar esa información como parte de un script o de forma interactiva en el indicador de shell.
En el indicador de shell, el caso de uso típico es: este comando se comporta de manera extraña, ¿estoy usando el ¿Qué ocurrió exactamente cuando escribí mycmd
? ¿Puedo ver más a fondo qué es?
En ese caso, desea saber qué hace su shell cuando invoca el comando sin invocar realmente el comando.
En los scripts de shell, tiende a ser bastante diferente. En un script de shell no hay ninguna razón por la que desee saber dónde o qué es un comando si todo lo que desea hacer es ejecutarlo. Por lo general, lo que desea saber es la ruta del ejecutable, por lo que puede obtener más información (como la ruta a otro archivo en relación con ese, o leer información del contenido del archivo ejecutable en esa ruta).
De forma interactiva, es posible que desee conocer todos los my-cmd
comandos disponibles en el sistema, en scripts, rara vez.
La mayoría de las herramientas disponibles (como suele ser el caso) han sido diseñadas para usarse de forma interactiva.
Historia
Primero un poco de historia.
Las primeras shells de Unix hasta finales de los 70 no tenían funciones ni alias. Solo la búsqueda tradicional de ejecutables en $PATH
. csh
introdujo alias alrededor de 1978 (aunque csh
se lanzó por primera vez en 2BSD
, en mayo de 1979), y también el procesamiento de un .cshrc
para que los usuarios personalicen el shell (cada shell, como csh
, lee .cshrc
incluso cuando no es interactivo como en los scripts).
Si bien el shell Bourne se lanzó por primera vez en Unix V7 a principios de 1979, el soporte de funciones solo se agregó mucho más tarde (1984 en SVR2), y de todos modos, nunca tuvo algún archivo rc
(el .profile
es para configurar su entorno, no el shell per se ).
csh
se volvió mucho más popular que el shell Bourne como (aunque tenía una sintaxis terriblemente peor que el Bourne) estaba agregando muchas características más convenientes y agradables para uso interactivo.
En 3BSD
(1980), un which
script csh se agregó para los csh
usuarios para ayudar a identificar un ejecutable, y es un script apenas diferente que puede encontrar como which
en muchos Unices comerciales hoy en día (como Solaris, HP / UX, AIX o Tru64).
Ese script lee el usuario» s ~/.cshrc
(como todas las secuencias de comandos csh
a menos que se invoquen con csh -f
), y busca los nombres de comando proporcionados en la lista de alias y en $path
(la matriz que csh
mantiene basada en $PATH
).
Aquí tienes: which
llegó primero para el shell más popular en ese momento (y csh
siguió siendo popular hasta mediados de 90), que es la razón principal por la que se documentó en libros y todavía se usa ampliamente.
Tenga en cuenta que, incluso para un csh
usuario, ese which
El script csh no necesariamente le da la información correcta. Obtiene los alias definidos en ~/.cshrc
, no los que puede haber definido más adelante en el indicador o, por ejemplo, source
en otro csh
archivo y (aunque eso no sería una buena idea), PATH
podría redefinirse en ~/.cshrc
.
Ejecutar ese which
comando desde un shell Bourne aún buscaría los alias definidos en su ~/.cshrc
, pero si no tiene uno porque no usa csh
, probablemente obtendrá la respuesta correcta.
No se agregó una funcionalidad similar a el shell Bourne hasta 1984 en SVR2 con el comando interno type
. El hecho de que esté integrado (a diferencia de un script externo) significa que puede brindarle la información correcta (hasta cierto punto) ya que tiene acceso a las partes internas del shell.
El comando type
inicial sufrió un problema similar al de la secuencia de comandos which
en el sentido de que no devolvió un estado de salida de falla si no se encontró el comando. Además, para los ejecutables, a diferencia de which
, genera algo como ls is /bin/ls
en lugar de solo /bin/ls
que lo hacía menos fácil de usar en scripts.
Unix Versión 8″ s (no lanzado en la naturaleza) Bourne shell lo tenía «s type
incorporado renombrado a whatis
. Y el shell Plan9 (el futuro sucesor de Unix) rc
(y su derivados como akanga
y es
) también tienen whatis
.
El caparazón de Korn (un subconjunto del cual el POSIX sh
se basa en la definición), desarrollado a mediados de los 80 pero no disponible antes de 1988, agregó muchas de las csh
características ( editor de línea, alias …) en la parte superior del shell Bourne. Agregó su propio whence
incorporado (además de type
) que tomó varias opciones (-v
para proporcionar el resultado detallado type
, y -p
para buscar solo ejecutables (no alias / funciones …)) .
Coincidiendo con la confusión con respecto a los problemas de derechos de autor entre AT & T y Berkeley, surgieron algunas implementaciones de shell de software libre a finales de los 80 y principios de los 90.Todo el shell Almquist (ash
, para reemplazar el shell Bourne en BSD), la implementación de dominio público de ksh
(pdksh
), bash
(patrocinado por la FSF), zsh
se publicó entre 1989 y 1991.
Ash, aunque estaba destinado a ser un reemplazo del shell Bourne, no tenía un type
incorporado hasta mucho más tarde (en NetBSD 1.3 y FreeBSD 2.3 ), aunque tenía hash -v
. OSF / 1 /bin/sh
tenía un type
incorporado que siempre devolvió 0 hasta OSF / 1 v3.x. bash
no agregó un whence
pero agregó un -p
opción a type
para imprimir la ruta (type -p
sería como whence -p
) y -a
para informar todos los comandos coincidentes. tcsh
hizo which
incorporado y agregó un where
comando que actúa como bash
» s type -a
. zsh
los tiene todos.
El fish
shell (2005) tiene un comando type
implementado como una función.
El which
mientras tanto, el script csh se eliminó de NetBSD (ya que estaba integrado en tcsh y no era de mucha utilidad en otros shells), y la funcionalidad se agregó a whereis
(cuando se invoca como which
, whereis
se comporta como which
excepto que solo busca ejecutables en $PATH
). En OpenBSD y FreeBSD, which
también se cambió a uno escrito en C que busca comandos en $PATH
únicamente .
Implementaciones
Hay docenas de implementaciones de un which
co mmand en varios Unices con diferente sintaxis y comportamiento.
En Linux (además de los integrados en tcsh
y zsh
) encontramos varias implementaciones. En sistemas Debian recientes, por ejemplo, es «un script de shell POSIX simple que busca comandos en $PATH
.
busybox
también tiene un which
comando.
Hay un GNU
which
que es probablemente el más extravagante. Intenta extender lo que el script which
csh hizo a otros shells: puede decirle cuáles son sus alias y funciones para que pueda dar tienes una mejor respuesta (y creo que algunas distribuciones de Linux establecen algunos alias globales para que bash
lo haga).
zsh
tiene un par de operadores para expandir a la ruta de los ejecutables: el operador =
expansión de nombre de archivo y el :c
modificador de expansión de historial (aquí aplicado a expansión de parámetros ):
$ print -r -- =ls /bin/ls $ cmd=ls; print -r -- $cmd:c /bin/ls
zsh
, en el también hace que la tabla hash de comandos sea la commands
matriz asociativa:
$ print -r -- $commands[ls] /bin/ls
La utilidad whatis
(excepto la de Unix V8 Bourne shell o Plan 9 rc
/ es
) no está realmente relacionado, ya que «es solo para documentación (greps la base de datos whatis, que es la sinopsis de la página de manual»).
whereis
también añadido en 3BSD
al mismo tiempo que which
aunque estaba escrito en C
, no csh
y se utiliza para buscar al mismo tiempo el ejecutable, la página de manual y la fuente, pero no se basa en el entorno actual. De nuevo, eso responde a una necesidad diferente.
Ahora, en el frente estándar, POSIX especifica command -v
y -V
comandos (que solían ser opcionales hasta POSIX.2008). UNIX especifica el comando type
(sin opción). Eso es todo (where
, which
, whence
no se especifican en ningún estándar) .
Hasta algunas versiones, type
y command -v
eran opcionales en la especificación de la base estándar de Linux, lo que explica por qué Por ejemplo, algunas versiones antiguas de posh
(aunque basadas en pdksh
que tenían ambas) no tenían ninguna. command -v
también se agregó a algunas implementaciones de shell Bourne (como en Solaris).
Estado actual
El estado actual es que type
y command -v
son ubicuos en todos los shells tipo Bourne (aunque, como lo señaló @jarno, tenga en cuenta la advertencia / error en bash
cuando no está en modo POSIX o algunos descendientes del shell Almquist a continuación en los comentarios). tcsh
es el único shell en el que le gustaría usar which
(ya que «no hay type
allí y which
está incorporado).
En los shells que no sean tcsh
y zsh
, which
puede indicarle la ruta del ejecutable dado siempre que no haya un alias o función con el mismo nombre en cualquiera de nuestros ~/.cshrc
, ~/.bashrc
o cualquier archivo de inicio de shell y no «define $PATH
en su ~/.cshrc
. Si tiene un alias o una función definida para él, puede que le informe o no, o le diga algo incorrecto.
Si quiere saber sobre todos los comandos con un nombre dado, no hay nada portátil. «Usarías where
en tcsh
o zsh
, type -a
en bash
o zsh
, whence -a
en ksh93 y en otros shells , puede usar type
en combinación con which -a
que puede funcionar.
Recomendaciones
Obtener el nombre de la ruta de un ejecutable
Ahora, para obtener el nombre de la ruta de un ejecutable en un script, hay algunas advertencias:
ls=$(command -v ls)
sería la forma estándar de hacerlo.
Sin embargo, existen algunos problemas:
- No es posible conocer la ruta del ejecutable sin ejecutarlo.
type
,which
,command -v
… todos usan heurísticas para averiguar la ruta . Recorren los componentes$PATH
y encuentran el primer archivo que no es de directorio para el que tiene permiso de ejecución. Sin embargo, depe Al encontrar en el shell, cuando se trata de ejecutar el comando, muchos de ellos (Bourne, AT & T ksh, zsh, ash …) simplemente los ejecutarán en el orden de$PATH
hasta que la llamada al sistemaexecve
no regrese con un error. Por ejemplo, si$PATH
contiene/foo:/bar
y quieres ejecutarls
, primero intentarán para ejecutar/foo/ls
o si eso falla/bar/ls
. Ahora la ejecución de/foo/ls
puede fallar porque no tiene permiso de ejecución, pero también por muchas otras razones, como si no fuera un ejecutable válido.command -v ls
informaría/foo/ls
si tiene permiso de ejecución para/foo/ls
, pero ejecutals
podría ejecutar/bar/ls
si/foo/ls
no es un ejecutable válido. - si
foo
es una función o un alias incorporado,command -v foo
devuelvefoo
. Con algunos shells comoash
,pdksh
ozsh
, también puede devolverfoo
si$PATH
incluye la cadena vacía y hay un archivofoo
ejecutable en el directorio actual. Hay algunas circunstancias en las que es posible que deba tener eso en cuenta. Tenga en cuenta, por ejemplo, que la lista de elementos integrados varía con la implementación del shell (por ejemplo,mount
a veces está integrado para busyboxsh
) y, por ejemplo,bash
puede obtener funciones del entorno. - if
$PATH
contiene componentes de ruta relativa (normalmente.
o la cadena vacía que se refieren al directorio actual pero podrían ser cualquier cosa), según el shell,command -v cmd
no genere una ruta absoluta. Por lo tanto, la ruta que obtiene en el momento en que ejecuta ya no será válido después decd
en otro lugar. - Anecdótico: con el shell ksh93, si
/opt/ast/bin
(aunque creo que esa ruta exacta puede variar en diferentes sistemas) está en ti$PATH
, ksh93 pondrá a disposición algunas incorporaciones adicionales (chmod
,cmp
,cat
…), perocommand -v chmod
devolverá/opt/ast/bin/chmod
incluso si esa ruta no existe.
Determinación de si existe un comando
Para averiguar si un comando determinado existe de manera estándar, puede hacer:
if command -v given-command > /dev/null 2>&1; then echo given-command is available else echo given-command is not available fi
Donde uno podría querer usar which
(t)csh
En csh
y tcsh
, no tienes muchas opciones. En tcsh
, eso «Está bien, ya que which
está integrado. En csh
, ese será el comando del sistema which
, que puede no hacer lo que usted desea en algunos casos.
Buscar comandos solo en algunos shells
Un caso en el que podría tener sentido usar which
es si desea conocer la ruta de un comando, ignorando el potencial funciones o incorporaciones de shell en bash
, csh
(no tcsh
), dash
, o Bourne
scripts de shell, es decir, shells que «no tienen whence -p
(como ksh
o zsh
), command -ev
(como yash
), whatis -p
(rc
, akanga
) o una which
(como tcsh
o zsh
) en sistemas donde which
es disponible y no es el csh
script.
Si se cumplen esas condiciones, entonces:
echo=$(which echo)
le daría la ruta del primer echo
en $PATH
(excepto en los casos de esquina), independientemente de si echo
también es un shell función incorporada / alias / o no.
En otros shells, preferiría:
- zsh :
echo==echo
oecho=$commands[echo]
oecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- yash :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`
(cuidado con las rutas con espacios) - pez :
set echo (type -fp echo)
Tenga en cuenta que si todo lo que quiere hacer es ejecutar ese echo
comando, no tiene que obtener su ruta, solo puede hacer:
env echo this is not echoed by the builtin echo
Por ejemplo, con tcsh
, para evitar que se utilice el which
incorporado:
set Echo = "`env which echo`"
Cuando necesita un comando externo
Otro caso en el que puede querer usar which
es cuando realmente necesita un comando externo. POSIX requiere que todos los comandos internos de shell (como command
) también estén disponibles como comandos externos, pero desafortunadamente, ese «no es el caso para command
en muchos sistemas. Por ejemplo, es raro encontrar un comando command
en sistemas operativos basados en Linux, mientras que la mayoría de ellos tienen un which
comando (aunque diferentes con diferentes opciones y comportamientos).
Los casos en los que podría querer un comando externo serían donde ejecutaría un comando sin invocar un shell POSIX.
El system("some command line")
, popen()
… las funciones de C o varios lenguajes invocan un shell para analizar esa línea de comandos, por lo que system("command -v my-cmd")
trabaja en ellos. Una excepción sería perl
que optimiza el shell si no ve ningún carácter especial del shell (que no sea el espacio). Eso también se aplica a su operador de comillas invertidas:
$ 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
La adición de ese :;
anterior obliga a perl
a invocar un shell allí. Al usar which
, no tendría que usar ese truco.
Comentarios
- @Joe,
which
es un scriptcsh
en muchos Unices comerciales. La razón es histórica, que ‘ es la razón por la que di el historial, para que la gente entienda de dónde viene, por qué la gente se acostumbró a usarlo y por qué en realidad hay ‘ s no hay razón para que deba usarlo. Y sí, algunas personas usan (t) csh. No todo el mundo usa Linux todavía - Después de leer esta publicación, he encontrado mucho contexto para la respuesta, pero no la respuesta en sí.¿Dónde en esta publicación dice realmente por qué no usar
which
, a diferencia de las cosas que podría estar intentando usarwhich
que hacer, el historial dewhich
, las implementaciones dewhich
, otros comandos para realizar tareas relacionadas o las razones para usarwhich
? ¿Por qué los otros comandos son mejores ? ¿Qué hacen de manera diferente awhich
? ¿Cómo evitan sus trampas? Esta respuesta en realidad gasta más palabras en los problemas con las alternativas que en los problemas conwhich
. -
command
se describe por POSIX. - @St é phaneChazelas Si creo un nuevo archivo con
touch /usr/bin/mytestfile
y luego ejecutocommand -v mytestfile
, dará la ruta (mientras quewhich mytestfile
no). - @jarno, oh sí, tú ‘ derecho.
bash
se decidirá por un archivo no ejecutable si ‘ t encontrar uno ejecutable, por lo que ‘ s » OK » (aunque en la práctica uno preferiríacommand -v
/type
devuelve un error) ya que ‘ es el comando que intentaría ejecutar cuando ejecutamytestfile
, pero el comportamientodash
tiene errores, como si hubiera ‘ uncmd
antes de uno ejecutable,command -v
devuelve el no ejecutable mientras que la ejecución decmd
ejecutaría el ejecutable (el uno también tiene hash). FreeBSDsh
(también basado enash
) tiene el mismo error. zsh, yash, ksh, mksh, bash como sh están bien.
Responder
Las razones por las que uno puede No quiero usar which
ya se han explicado, pero aquí hay algunos ejemplos en algunos sistemas en los que which
realmente falla.
En shells de tipo Bourne, «estamos comparando la salida de which
con la salida de type
(type
siendo un intérprete de órdenes incorporado, está destinado a ser la verdad básica, ya que es el intérprete de órdenes diciéndonos cómo invocaría un comando).
Muchos casos son casos de esquina , pero tenga en cuenta que which
/ type
se utilizan a menudo en casos de esquina (para encontrar la respuesta a un comportamiento inesperado como: ¿por qué diablos ese comando se comporta así, a cuál estoy llamando? ).
La mayoría de los sistemas, la mayoría de shells tipo Bourne: funciones
El caso más obvio es para las funciones:
$ type ls ls is a function ls () { [ -t 1 ] && set -- -F "$@"; command ls "$@" } $ which ls /bin/ls
La razón es que which
solo informa sobre ejecutables y, a veces, sobre alias (aunque no siempre los de su shell), no funciones.
El GNU cuya página de manual tiene un ejemplo roto (ya que se olvidaron de citar $@
) sobre cómo usarlo para informar funciones también, pero al igual que para alias, debido a que no implementa un analizador de sintaxis de shell, es fácil de engañar:
$ 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; }
La mayoría de los sistemas, la mayoría de los shells tipo Bourne: incorporados
Otro caso obvio son las incorporaciones o palabras clave, ya que which
siendo un comando externo no tiene forma de saber qué incorporaciones tiene tu shell (y algunas shells como zsh
, bash
o ksh
pueden cargar archivos integrados de forma dinámica):
$ 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
(eso no «se aplica a zsh
donde which
está integrado)
Solaris 10, AIX 7.1, HP / UX 11i, Tru64 5. 1 y muchos otros:
$ 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
Eso se debe a que en la mayoría de los Unices comerciales, which
(como en la implementación original en 3BSD) es un csh
script que dice ~/.cshrc
. Los alias que informará son los definidos allí independientemente de los alias que haya definido actualmente e independientemente del shell que esté utilizando realmente.
En HP / UX o Tru64:
% echo "setenv PATH /bin:/usr/bin" >> ~/.cshrc % setenv PATH ~/bin:/bin:/usr/bin % ln -s /bin/ls ~/bin/ % which ls /bin/ls
(las versiones de Solaris y AIX han solucionado ese problema guardando $path
antes de leer el ~/.cshrc
y restaurarlo antes de buscar los comandos)
$ 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
O:
$ 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
(por supuesto, al ser un script csh
, no puede «esperar que funcione con argumentos que contengan espacios …)
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="
En ese sistema, hay un alias definido en todo el sistema que envuelve el comando GNU which
.
La salida falsa se debe a que which
lee la salida de bash
«s alias
pero no sabe cómo analizarlo correctamente y usa heurísticas (un alias por línea, busca el primer comando encontrado después de |
, ;
, &
…)
Lo peor en CentOS es que zsh
tiene un comando interno which
perfectamente correcto, pero CentOS logró romperlo reemplazándolo con un alias que no funciona para GNU which
.
Debian 7.0, ksh93:
(aunque se aplica a la mayoría de los sistemas con muchos shells)
$ unset PATH $ which which /usr/local/bin/which $ type which which is a tracked alias for /bin/which
En Debian, /bin/which
es una secuencia de comandos /bin/sh
. En mi caso, sh
es dash
pero «es lo mismo cuando» es bash
.
Un PATH
no establecido no es para deshabilitar la búsqueda de PATH
, sino que significa usar el sistema «s RUTA predeterminada que desafortunadamente en Debian, nadie está de acuerdo (dash
y bash
tienen /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
tiene /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
tiene /bin:/usr/bin
, mksh
tiene /usr/bin:/bin
($(getconf PATH)
), execvp()
(como en env
) tiene :/bin:/usr/bin
(sí, primero busca en el directorio actual)) .
Por eso which
se equivoca anteriormente, ya que «está usando dash
» la PATH
que es diferente de ksh93
«s
No t mejor con GNU which
que informa:
which: no which in ((null))
(curiosamente, de hecho hay un /usr/local/bin/which
en mi sistema, que en realidad es una secuencia de comandos akanga
que viene con akanga
(una rc
derivado de shell donde el PATH
predeterminado es /usr/ucb:/usr/bin:/bin:.
))
bash, cualquier sistema:
El a quien Chris se refiere en su respuesta :
$ 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
También después de llamar a hash
manualmente:
$ 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)
Ahora un caso donde which
y algunas veces type
fallan:
$ 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
Ahora, con algunos shells:
$ foo bash: ./b/foo: /: bad interpreter: Permission denied
Con otros:
$ foo a/foo
Ni which
ni type
puede saber de antemano que b/foo
no puede b e ejecutado. Algunas shells como bash
, ksh
o yash
, al invocar foo
de hecho intentará ejecutar b/foo
e informar un error, mientras que otros (como zsh
, ash
, csh
, Bourne
, tcsh
) se ejecutarán a/foo
tras la falla de la llamada del sistema execve()
en b/foo
.
Comentarios
-
mksh
en realidad usa algo diferente para el$PATH
predeterminado: primero , se usa la constante de tiempo de compilación del sistema operativo_PATH_DEFPATH
(más comúnmente en los BSD), luego, se usaconfstr(_CS_PATH, …)
(POSIX), y si ambos no existen o fallan, se usa/bin:/usr/bin:/sbin:/usr/sbin
. - En su primer ejemplo, incluso si
ls
es una función que está usando gls
de PATH. Ywhich
está bien para decirte cuál se usa/usr/bin/ls
o/usr/local/bin/ls
. No ‘ t ver » ¿Por qué no usar cuál » …. - @rudimeier, que
which ls
me dará/bin/ls
independientemente de si ells
la función llama a/bin/ls
o/opt/gnu/bin/ls
odir
o nada en absoluto. IOW,which
(aquello que implementaciones, IMMV) está dando algo irrelevante - @St é phaneChazelas. No no no. Ya sé que mi
ls
es una función. sé que mils
función llama als
desdePATH
. Ahorawhich
me dice dónde está el archivo. Solo ve un caso de uso único: » ¿Qué haría mi shell con este comando? » Para este caso de usowhich
es incorrecto, correcto.Pero hay otros casos de uso en los que (GNU)which
es exactamente lo correcto. - @rudimeter, depende de
which
implementación. Algunos te dirán que ‘ es un alias (si tienes un alias configurado o si hay un~/.cshrc
en tu casa que tiene tal alias), algunos le darán una ruta pero la incorrecta en algunas condiciones.sh -c 'command -v ls'
, aunque no es perfecto, es más probable que le dé la respuesta correcta a ese requisito diferente (y también es estándar).
Answer
Una cosa que (según mi rápido vistazo) parece que Stephane no mencionó es que which
tiene ni idea de la tabla hash de ruta de su shell. Esto tiene el efecto de que puede devolver un resultado que no es representativo de lo que realmente se ejecuta, lo que lo hace ineficaz en la depuración.
Respuesta
Por lo general, me estremezco cuando se recomienda esta pregunta a usuarios desprevenidos porque atacar sin fundamento which
no es útil para nadie.
Si which
funciona bien y proporciona la respuesta correcta a alguna tarea, siguiendo el modelo de Unix: haz una cosa, hazlo bien , ¿por qué debería which
ser prohibido?
La pregunta debería ser, entonces, ¿cuál funciona bien y hace bien un trabajo específico?
Por un lado, la utilidad externa en / bin / que en Debian es un script de shell cuyo objetivo es solo listar los ejecutables del nombre dado en la ruta. Creo que which
cumple correctamente su objetivo previsto. No carga ningún alias, ninguna función, nada del shell, solo enumera los primeros (o todos) los ejecutables del nombre de pila en la RUTA. El que significa de haber encontrado un archivo con el mismo nombre dado es algo que el usuario debe averiguar por ella (él) self.
Sí, otras which
implementaciones pueden (y normalmente tienen) tener problemas particulares.
Respuesta
A menudo escuchamos lo que debe evitarse. ¿Por qué? ¿Qué deberíamos usar en su lugar?
Nunca escuché eso. Proporcione ejemplos específicos. Me preocuparía por su distribución de Linux y los paquetes de software instalados, ya que es de donde viene which
!
SLES 11.4 x86-64
en tcsh versión 6.18.01:
> which which which: shell built-in command.
en bash versión 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
es parte de util-linux un paquete estándar distribuido por la Organización del Kernel de Linux para su uso como parte del sistema operativo Linux. También proporciona estos otros archivos
/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
my util-linux
es la versión 2.19. Las notas de la versión se pueden encontrar fácilmente desde la versión 2.13 con fecha (28 de agosto de 2007). No estoy seguro de cuál era el objetivo o el objetivo de esto, ciertamente no fue respondido en ese largo mensaje votado 331 veces.
Comentarios
- Observe cómo La pregunta no menciona a qué Unix se refiere. Linux es solo uno de algunos.
- Como muestra su
which -v
, ese ‘ s GNU que (el extravagante uno mencionado en la otra respuesta y de ninguna manera es específico de Linux), no util-linux, que AFAIK nunca incluyó una utilidadwhich
. util-linux 2.19 es de 2011, GNU que 2.19 es de 2008.
which
están asumiendo un contexto de shell interactivo. Esta pregunta está etiquetada / portabilidad. Así que interpreto la pregunta en este contexto como » qué usar en lugar dewhich
para encontrar el primer ejecutable de un nombre dado en el$PATH
«. La mayoría de las respuestas y razones en contrawhich
trata con alias, incorporaciones y funciones, que en la mayoría de los scripts de shell portátiles del mundo real son solo de interés académico. Los alias definidos localmente no son ‘ t heredados cuando se ejecuta un script de shell (a menos que lo obtenga con.
).csh
(ywhich
sigue siendo una secuencia de comandoscsh
en la mayoría de Unices) lee~/.cshrc
cuando no es interactivo. Esa ‘ es la razón por la que ‘ notarás que los scripts csh generalmente comienzan con#! /bin/csh -f
.which
no lo hace porque tiene como objetivo darte los alias, porque ‘ es una herramienta para usuarios (interactivos) decsh
. Los usuarios de shells POSIX tienencommand -v
.(t)csh
(o no ‘ te importa si no ‘ no te da el resultado correcto), usatype
ocommand -v
en su lugar . Vea las respuestas para por qué .stat $(which ls)
es incorrecto por varias razones (falta--
, comillas faltantes), no solo el uso dewhich
). Usted ‘ usaríastat -- "$(command -v ls)"
. Eso supone quels
es de hecho un comando que se encuentra en el sistema de archivos (no una función incorporada de su shell, o una función de alias).which
puede darle la ruta incorrecta (no la ruta que su shell ejecutaría si ingresarals
) o darle un alias como se define en la configuración de algunos otros shells …which
implementaciones no le darían ni siquiera ells
que se encontrarían mediante una búsqueda de$PATH
(independientemente de lo quels
puede invocar en su caparazón).sh -c 'command -v ls'
ozsh -c 'rpm -q --whatprovides =ls'
son más propensos a darte la respuesta correcta. El punto aquí es quewhich
es una herencia rota decsh
.