Los programas típicos de Unix / Linux aceptan las entradas de la línea de comandos como un conteo de argumentos ( int argc
) y un vector de argumentos ( char *argv[]
). El primer elemento de argv
es el nombre del programa, seguido de los argumentos reales.
¿Por qué se pasa el nombre del programa al ejecutable como argumento? ¿Hay ejemplos de programas que usen su propio nombre (tal vez algún tipo de exec
situación)?
command-line
c
arguments
Shrikant Giridhar
fuente
fuente
sh
es enlace simbólico adash
. Se comportan de manera diferente, cuando se les llama comosh
o comodash
busybox
(común en los discos de rescate y demás ), casi todo (cp, mv, rm, ls, ...) es un enlace simbólico a busybox.gcc
,bash
,gunzip
, la mayor parte del resto del OS ...), ya que Linux es sólo el núcleo.Respuestas:
Para empezar, tenga en cuenta que
argv[0]
no es necesariamente el nombre del programa. Es lo que la persona que llama pone enargv[0]
laexecve
llamada del sistema (por ejemplo, vea esta pregunta en Desbordamiento de pila ). (Todas las demás variantes deexec
no son llamadas al sistema sino interfaces aexecve
).Supongamos, por ejemplo, lo siguiente (usando
execl
):/var/tmp/mybackdoor
es lo que se ejecuta peroargv[0]
se establece entop
, y esto es lo queps
o (lo real)top
mostraría. Vea esta respuesta en U&L SE para más información sobre esto.Dejando a un lado todo esto: antes de la aparición de sofisticados sistemas de archivos como
/proc
,argv[0]
era la única forma de que un proceso aprendiera sobre su propio nombre. ¿Para qué sería bueno?fuente
bunzip2
,bzcat
ybzip2
, para los cuales los dos primeros son enlaces simbólicos al tercero.zcat
no es un enlace simbólico. Parecen evitar las desventajas de esta técnica utilizando un script de shell en su lugar. Pero no pueden imprimir una--help
salida completa porque alguien que agregó opciones a gzip también olvidó mantener zcat.gunzip
Es una excepción histórica.argv[0]
salida de uso / ayuda en lugar de codificar su nombre. Algunos en su totalidad, algunos solo el nombre base.Mucho:
argv[0]
estásh
. Se ejecuta como un shell de inicio de sesión cuandoargv[0]
comienza con-
.vi
,view
,evim
,eview
,ex
,vimdiff
, etc.shutdown
,reboot
, etc., son enlaces simbólicos asystemctl
.fuente
sendmail
ymail
. Cada MTA de Unix viene con un enlace simbólico para esos dos comandos, y está diseñado para emular el comportamiento del original cuando se llama como tal, lo que significa que cualquier programa de Unix que necesite enviar correo sabe exactamente cómo puede hacerlo.test
y[
: cuando llamas al primero, maneja un error si el último argumento es]
. (en Debian estable, estos comandos son dos programas diferentes, pero las versiones anteriores y MacOs todavía usan el mismo programa). Ytex
,latex
y así sucesivamente: el binario es el mismo, pero mirando cómo se llama, es elegir el correcto configuración de archivo.init
es similar.[
considera un error si el último argumento no lo es]
.Históricamente,
argv
es solo una serie de punteros a las "palabras" de la línea de comandos, por lo que tiene sentido comenzar con la primera "palabra", que resulta ser el nombre del programa.Y hay bastantes programas que se comportan de manera diferente según el nombre que se use para llamarlos, por lo que puede crear diferentes enlaces a ellos y obtener diferentes "comandos". El ejemplo más extremo que se me ocurre es busybox , que actúa como varias docenas de "comandos" diferentes según cómo se llame .
Editar : Referencias para Unix 1st edition, según lo solicitado
Uno puede ver, por ejemplo, desde la función principal de
cc
esoargc
yargv
ya se utilizaron. El shell copia argumentos en elparbuf
interior de lanewarg
parte del bucle, mientras trata el comando en sí de la misma manera que los argumentos. (Por supuesto, más adelante solo ejecuta el primer argumento, que es el nombre del comando). Parece que losexecv
parientes no existían entonces.fuente
exec
toma el nombre del comando a ejecutar y una matriz de punteros de caracteres con terminación cero (mejor visto en minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , dondeexec
toma referencias a la etiqueta 2 y la etiqueta 1, y en la etiqueta2:
apareceetc/init\0
, y en la etiqueta1:
aparece una referencia a la etiqueta 2, y un cero final), que es básicamente lo queexecve
hace hoy menosenvp
.execv
yexecl
han existido "para siempre" (es decir, desde principios hasta mediados de la década de 1970) -execv
fue una llamada al sistema yexecl
fue una función de biblioteca que la llamó.execve
no existía entonces porque el entorno no existía entonces. Los otros miembros de la familia fueron agregados más tarde.execv
en la fuente v1 que vinculé? Sólo curioso.Casos de uso:
Puede usar el nombre del programa para cambiar el comportamiento del programa .
Por ejemplo, podría crear algunos enlaces simbólicos al binario real.
Un ejemplo famoso en el que se utiliza esta técnica es el proyecto busybox que instala solo un binario único y muchos enlaces simbólicos. (ls, cp, mv, etc.) Lo están haciendo para ahorrar espacio de almacenamiento porque sus objetivos son pequeños dispositivos integrados.
Esto también se usa en
setarch
util-linux:Aquí están utilizando esta técnica básicamente para evitar muchos archivos fuente duplicados o simplemente para mantener las fuentes más legibles.
Otro caso de uso sería un programa que necesita cargar algunos módulos o datos en tiempo de ejecución. Tener la ruta del programa le permite cargar módulos desde una ruta relativa a la ubicación del programa .
Además, muchos programas imprimen mensajes de error, incluido el nombre del programa .
Por qué :
man 3p execve
):Tenga en cuenta que el estándar C dice "nombre del programa" no "nombre de archivo".
fuente
Además de los programas que alteran su comportamiento en función de cómo fueron llamados, me parece
argv[0]
útil imprimir el uso de un programa, así:Esto hace que el mensaje de uso use siempre el nombre a través del cual fue llamado. Si se cambia el nombre del programa, su mensaje de uso cambia con él. Incluso incluye el nombre de ruta con el que se llamó:
Es un buen toque, especialmente para pequeñas herramientas / scripts de propósito especial que podrían vivir en todo el lugar.
Esto también parece una práctica común en las herramientas GNU, ver
ls
por ejemplo:fuente
Uno ejecuta el programa tecleando:
program_name0 arg1 arg2 arg3 ...
.Entonces el shell ya debería dividir el token, y el primer token ya es el nombre del programa. Y, por cierto, existen los mismos índices en el lado del programa y en el shell.
Creo que esto fue solo un truco de conveniencia (muy al principio) y, como puede ver en otras respuestas, también fue muy útil, por lo que esta tradición se continuó y se estableció como API.
fuente
Básicamente, argv incluye el nombre del programa para que pueda escribir mensajes de error como
prgm: file: No such file or directory
, que se implementaría con algo como esto:fuente
Otro ejemplo de una aplicación de este es este programa, que se reemplaza por sí mismo ... hasta que escribe algo que no lo es
y
.Obviamente, es una especie de ejemplo ingenioso pero interesante, pero creo que esto puede tener usos reales, por ejemplo, un binario de actualización automática, que reescribe su propio espacio de memoria con una nueva versión de sí mismo que descargó o cambió.
Ejemplo:
Fuente, y algo más de información .
fuente
La ruta al programa es
argv[0]
, para que el programa pueda recuperar archivos de configuración, etc. de su directorio de instalación.Esto sería imposible sin él
argv[0]
.fuente
(char *path_to_program, char **argv, int argc)
por ejemplo~/.<program>
,/etc/<program
,$XDG_CONFIG_HOME
) y, o bien tomar un parámetro para cambiarlo o tiene una opción en tiempo de compilación que se hornea en una constante para el binario.ccache se comporta de esta manera para imitar diferentes llamadas a los binarios del compilador. ccache es una caché de compilación: el objetivo principal nunca es compilar el mismo código fuente dos veces, sino devolver el código objeto de la caché si es posible.
Desde la página de manual de ccache , "hay dos formas de usar ccache. Puede prefijar sus comandos de compilación con ccache o puede dejar que ccache se disfrace como compilador creando un enlace simbólico (llamado como compilador) a ccache. El primer método es más conveniente si solo desea probar ccache o desea usarlo para algunos proyectos específicos. El segundo método es más útil para cuando desea usar ccache para todas sus compilaciones ".
El método de enlaces simbólicos implica ejecutar estos comandos:
... cuyo efecto es permitir que ccache enganche cualquier comando que de otro modo hubiera ido a los compiladores, permitiendo así que ccache devuelva un archivo en caché o pase el comando al compilador real.
fuente