Ejecutar como .test en lugar de ./test

26

Suponiendo que estoy en la misma carpeta que un archivo ejecutable, necesitaría escribir esto para ejecutarlo:

./file

Preferiría no tener que escribir /, porque /es difícil para mí escribir.

¿Hay una manera más fácil de ejecutar un archivo? Idealmente, solo una sintaxis simple como:

.file

o algo más pero más fácil que tener que insertar el /personaje allí.

Quizás haya alguna forma de poner algo en el /bindirectorio, o crear un alias para el intérprete, de modo que pueda usar:

p file
IMSoP
fuente
9
¿Quizás intercambiar / con otra tecla usando xmodmap? Así que por lo menos es más fácil de escribir
individuo
26
Como nota al margen, /se usa ampliamente en Unix, en gran medida como un separador de directorio. Probablemente sea mejor encontrar una forma más fácil de escribirlo.
chrylis -on strike-
77
@RossPresser Esta pregunta tiene muy poco sentido desde entonces. y ./ al comienzo del archivo hay dos significados completamente diferentes por razones técnicas que cualquier principiante debe saber. /no es difícil de escribir para la gran mayoría de las personas, y si OP tiene una lesión que lo impide, deberían considerar diseños de teclado alternativos, ya que no hay forma de evitarlos /completamente mientras están en el terminal.
JFA
1
@JFA La mayoría de los diseños de teclado utilizados en Europa continental y Sudamérica utilizan /shift-7, que es relativamente difícil de escribir, incluso sin lesiones.
nitro2k01
66
Editar historial: " ¿por qué la interfaz de red no puede recibir instrucciones para realizar todas las consultas de Internet a través de un host remoto a través de ssh en el puerto 22. " ಠ_ಠ
Derek 朕 會 功夫

Respuestas:

35

Puede ser "arriesgado", pero podría haberlo hecho. en tu camino.

Como se ha dicho en otros, esto puede ser peligroso, así que asegúrese siempre. está al final de la RUTA y no al principio.

HaloJones
fuente
1
Realmente no veo cómo eso es "arriesgado": mi camino ha sido así desde mucho antes de Linux, y nunca ha causado el menor problema.
jamesqf
21
@jamesqf Es arriesgado porque si va cda un directorio que se puede escribir en todo el mundo e intenta utilizar un comando que no está en su ruta, podría ejecutar un ejecutable (posiblemente malicioso) con el mismo nombre que alguien escribió en esa ruta. Esto es mucho peor si lo pones .al comienzo de tu camino. En ese caso, lsse ejecutará un ejecutable malicioso llamado si intenta llamar lsa ese directorio.
bytesized
2
Evite esto, por los motivos especificados anteriormente. El pcomando sería mejor.
Guido
11
@jamesqf Cuando es "tu" sistema, y ​​solo tú lo usas, no es tan malo. El problema surge (y ha tropezado con muchos administradores de Unix a lo largo de los años) en un sistema multiusuario. Al .principio PATH, todo lo que un usuario malintencionado debe hacer es soltar un lscomando falso en su directorio y persuadir al administrador para que "mire algo extraño" y tenga acceso a la raíz.
TripeHound
1
Buena solución, aunque no funcionará si el archivo se nombra test, como en el título de la pregunta (ya que testes un shell incorporado, y probablemente también exista en algún lugar de su archivo $PATH).
yellowantphil
71

.se completará automáticamente para./ (escribir .y presionar Tab) al menos en los shells Bash modernos, por lo que no debería tener que usar una PATHsolución compleja o insegura (como la modificación).

Si no se completa automáticamente, es posible que deba instalar el paquete "bash-complete".

l0b0
fuente
¿Estás seguro? .tiene múltiples candidatos de finalización: .(directorio actual), ..(directorio principal), el .comando (que bash proporciona un alias no estándar sourcepara) y cualquier archivo de puntos presente. Tal vez el bash-completionpaquete ignora esto; Lo encuentro atrozmente molesto (por ejemplo, hace que sea imposible completar con tabulación los nombres de directorios en una makelínea de comando y, en general, es horrible con archivos Makefiles llenos de reglas implícitas), por lo que siempre lo purgo.
R ..
3
Lo probé, y sí, se completa automáticamente de esta manera. En casi todos los casos, eso es lo que un usuario normal desearía: no creo haber visto nunca un archivo de puntos que deba ser ejecutable, ejecutar algo en un subdirectorio es mucho más común que ejecutar algo en un directorio principal, y en mi opinión lo hace. un maldito buen trabajo para encontrar makeobjetivos.
l0b0
Con bash 3.2 no se completa automáticamente. ¿Podría ser esto nuevo en bash 4?
Calimo
2
@Calimo Más probablemente nuevo en versiones recientes de bash-complete. Está lejos de ser un cambio fundamental.
l0b0
42

o ... quizás dándole al intérprete un alias en el archivo bashrc y luego simplemente

   p  file

Es posible escribir tal función:

p() {
 ./"$@"
}

en su ~/.bashrc. Entonces podrás correr en p app argumentslugar de ./app arguments. Esta solución funciona para ejecutables de cualquier tipo, incluidos scripts y binarios.

"$@"se expande a la lista de argumentos entregados apropiadamente a la función (preservando todos los caracteres especiales de la expansión global o variable) y, como señaló @Scott, bashes lo suficientemente inteligente como para anteponer ./al primero de ellos, preservando el resto.

aitap
fuente
Aunque es menos general para ejecutar la aplicación bajo otro comando, como strace -f p appver las llamadas realizadas al sistema o $(which time) p appver cuánto tiempo lleva. pcomo script ejecutable funcionaría mejor en estos dos ejemplos específicos que inventé. Ninguna de las soluciones podría funcionar ldd p app, aunque ldd también difiere en requerir un camino completo, tal vez por razones como esta.
sourcejedi
Sí, en sustitución p app argsde ./app argsuna manera que es invisible a cualquier persona requeriría tubería de entrada de la cáscara a través de algún tipo de preprocesador y causaría todo tipo de diversión cuando se produce la sustitución en un lugar no deseado :)
aitap
1
En este caso, ¿no debería haber citas $@? De lo contrario, solo pasará un gran argumento al programa.
Kroltan
77
@Kroltan No. $@es una matriz. Cuando se expande dentro ", cada parámetro se expande a una palabra separada. $*se comporta como estás pensando.
8bittree
3
Creo que has hecho esto innecesariamente complejo, y eso p() { ./"$@"; }es todo lo que necesitas.
Scott
11

Podrías ponerlo .en tu $PATHagregando, por ejemplo, PATH=$PATH:.a tu /etc/profile, de esta manera puedes ejecutarlo filesimplemente escribiendo file, a menos que esté en alguna otra carpeta en tu ruta (por ejemplo /usr/bin/). Tenga en cuenta que esto generalmente no es una buena idea.

Por qué es malo: supongamos que se encuentra en una situación en la que no confía plenamente en el contenido de un directorio: lo ha descargado de un lugar poco fiable y desea investigarlo antes de ejecutarlo, o es un administrador de sistemas que ayuda usuario buscando en su directorio de inicio, etc. Desea enumerar el directorio, por lo que intenta escribir ls, pero vaya, comete un error tipográfico y terminó escribiendo sl en su lugar. El autor de este directorio malicioso anticipó esto y colocó un script de shell llamado "sl" que ejecuta 'rm -rf --no-preserve-root /' (o algo más malicioso como instalar un rootkit).

(Gracias @ Muzer por la explicación)

phk
fuente
13
Aunque estoy totalmente de acuerdo, probablemente sea mejor explicar exactamente por qué esto no es una buena idea.
ymbirtt
16
Por qué es malo: supongamos que se encuentra en una situación en la que no confía plenamente en el contenido de un directorio: lo ha descargado de un lugar poco fiable y desea investigarlo antes de ejecutarlo, o es un administrador de sistemas que ayuda usuario buscando en su directorio de inicio, etc. Desea enumerar el directorio, por lo que intenta escribir ls, pero vaya, comete un error tipográfico y terminó escribiendo sl en su lugar. El autor de este directorio malicioso anticipó esto y colocó un script de shell llamado "sl" que ejecuta 'rm -rf --no-preserve-root /' (o algo más malicioso como instalar un rootkit).
Muzer
2
Vale la pena explicar que si el directorio actual está al comienzo de $ PATH, el atacante podría anular ls u otros comandos comunes
Délisson Junio
@ Muzer Huuuge sombreros de papel de aluminio aquí.
Sombrero Chicken
44
@GillBates Es el tipo de cosas de las que deberías tener cuidado como administrador de sistemas que tiene que lidiar con usuarios reales y potencialmente maliciosos, o alguien que analiza archivos sospechosos para ganarse la vida. Si ninguno de esos aplica, entonces estoy de acuerdo con usted. Sin embargo, todavía no creo que sea un buen hábito, porque nunca sabes cuándo cambiarán tus circunstancias, obtienes uno de estos trabajos y te maldecirás sin parar por haberte entrenado para confiar en un comportamiento inseguro; )
Muzer
10

Puedes llamar al intérprete, por ejemplo

bash test

En este caso, el script se ejecutará incluso si no tiene una línea shebang (por ejemplo #!/bin/bash) ni un bit ejecutable. Deberá conocer el intérprete correcto para ejecutarlo también. Puede leer la línea shebang del archivo primero para asegurarse de llamar al intérprete correcto, por ejemplo, si la línea shebang dice

#!/usr/bin/env python3

llamarías

python3 test
Zanna
fuente
77
el intérprete solo interpreta el código, no ejecutarán archivos binarios
Mc Kernel
Esta respuesta es algo lógica porque quizás al intérprete se le puede dar un alias en el archivo bashrc.
55
@McKernel buen punto, solo funciona si hay un intérprete, no para ejecutables compilados
Zanna
2
hay un intérprete para ejecutables compilados:/lib/ld.so
Dmitry Kudriavtsev
7

Hasta donde yo sé, no hay forma de lograrlo a menos que incluya el archivo en la ruta env, por lo que podría ejecutarlo simplemente escribiendo: file

.fileno funcionará ya que ese es un nombre de archivo diferente. Es un archivo llamado .filey no ./file.

Siento que la barra inclinada puede ser difícil de escribir para ti porque ¿quizás no hay un diseño en inglés? En ese caso, también me sucede a mí, por lo que frecuentemente cambio el diseño de mi teclado al inglés presionando Alt + Shift en Windows (uso Linux desde ssh)

Mc Kernel
fuente
7

La gente ha sugerido la adición .a PATH, lo cual es peligroso porque crea un riesgo de que accidentalmente ejecutar un programa malicioso plantado en un directorio con permisos de escritura. Pero, si tiene programas ejecutables en algunos directorios de su propiedad y se puede escribir sólo por usted, entonces es seguro (bastante seguro?) Para poner los director (es) en PATH, al añadir una línea como

PATH=$PATH:~/dev/myprog1:~/dev/myprog2

a su ~/.bashrcarchivo Por supuesto, esto significa que puede ejecutar un programa desde uno de esos directorios desde cualquier lugar del sistema de archivos. Por ejemplo, podría cd /etcy escribir foo, y se ejecutaría ~/dev/myprog1/foo. Esto tiene el inconveniente menor de que no puede tener programas con el mismo nombre en más de uno de los directorios. Específicamente, si tiene programas llamados foo en ambos ~/dev/myprog1y ~/dev/myprog2, no podrá ejecutar el segundo excepto especificando una ruta. Del mismo modo, si tiene un ~/dev/myprog1/cat...


Otro enfoque, si solo tiene unos pocos programas con los que hace esto, es definir alias para ellos:

alias gizmo='./gizmo'
alias gonzo='./gonzo'

O puede llamar a los alias .gizmoy .gonzo si lo encuentra más intuitivo.

En realidad, esto tiene, hasta cierto punto, el mismo riesgo de seguridad que poner .en su PATH. Si un usuario malintencionado puede leer su .bashrcy ver sus alias, entonces podría poner malware llamado gizmoy gonzoen directorios aleatorios con la esperanza de que lo ejecute. Es mejor hacer que estos usen nombres de ruta absolutos:

alias gizmo='~/dev/myprog1/gizmo'
alias gonzo='~/dev/myprog2/gonzo'

Por cierto, debe evitar nombrar un ejecutable test, ya que es un comando integrado de shell, y puede ejecutar un programa con ese nombre solo especificando una ruta o algún otro truco.

G-Man dice 'restablecer a Mónica'
fuente
Alternativamente, puede hacer una receta (si usa Makefiles) y hacer make gizmoo make gonzo.
ihato
Lo siento, pero no estoy seguro de entender cómo se relaciona eso con la pregunta o mi respuesta. ¿Está sugiriendo que el OP cree un Makefileen cada directorio, de modo que las acciones para make gizmofinalizar se ejecuten gizmo ? (1) Esa parece una forma incómoda de hacer lo mismo que la pfunción, sugerida en la pregunta, implementada inicialmente por aitap y refinada por Scott. (2) ¿Puedes pasar los argumentos de esa manera? ISTM que make gizmo arg1 arg2es equivalente a make gizmo; make arg1; make arg2.
G-Man dice 'Reincorporar a Monica'
1
(1) Quizás mi suposición es incorrecta, pero no me queda claro que OP quiera evitar el uso ./en todos los directorios . En mi opinión, está desarrollando algo y solo necesita ejecutar el programa producido con ./filefrecuencia. Realmente no puedo pensar en ningún otro escenario en el que con frecuencia sea necesario ejecutar un archivo local y si no lo está ejecutando con frecuencia no se molestaría en hacer la pregunta (dijo que no es imposible ) (2) en realidad no, pero puedes pasar los argumentos en la receta.
ihato
(1) Bueno, supongo que podemos estar de acuerdo en que la motivación del OP y el alcance de su pregunta no están claros. (2) Gracias por el enlace.
G-Man dice 'Reincorporar a Monica'
3

Para ampliar la respuesta de Zanna sobre intérpretes (lo siento, no hay representante para un comentario): un "intérprete" para ejecutables nativos (también conocidos como archivos binarios ELF) es el cargador dinámico ( ld.so), pero generalmente no entiende la sintaxis que desea:

$ /usr/lib/ld-linux-x86-64.so.2 program
program: error while loading shared libraries: program: cannot open shared object file
$ /usr/lib/ld-linux-x86-64.so.2 ./program
<program is launched>

(también, a menos que enlace simbólicamente ld.soen su ruta, aún necesitaría escribir /s)

bacondropped
fuente
Esto es específico de Linux, ¿verdad? ¿Podría explicar esto más, por qué funciona? Pensé que el kernel (Linux) haría el análisis y decidiría si y cómo ejecutar un binario, para eso binfmt_miscestá.
phk
2
@phk El archivo es específico de Linux, pero el concepto de un enlazador / cargador dinámico no lo es. Por ejemplo, FreeBSD tiene su propio /libexec/ld-elf.so.1. En Linux, no es tan simple como "decidir cómo ejecutar un binario": binfmt_miscdetecta el formato del archivo por números mágicos (ELF, shebang script, CIL). Después de eso, binfmt_elfse llama al controlador. Analiza encabezados y secciones ELF; .interpla sección contiene la ruta del cargador dinámico; el kernel inicia este cargador, realiza reubicaciones y salta a _start. En FreeBSD (no estoy seguro sobre otros) no hay binfmt, pero el principio es +/- similar.
bacondropped
1
@phk en cuanto a por qué esto funciona: ld.sono tiene .interpy está estáticamente vinculado, lo que significa que no necesita otro vinculador / cargador dinámico para resolver sus símbolos externos y hacer cálculos de reubicación.
bacondropped
ISTR Solaris también tiene algo equivalente a esto.
G-Man dice 'Restablece a Monica'
3

Si se nos permite comenzar a configurar cosas

mkdir -p ~/.local/bin
cat > ~/.local/bin/x << 'EOF'
#!/bin/sh
N="$1"
shift
exec "./$N" "$@"
EOF
chmod a+x ~/.local/bin/x

La mayoría de las distribuciones modernas incluyen ~ / .local / bin en $ PATH ya (agregue export PATH="$HOME/.local/bin:$PATH"a su ~/.profilesi la suya no lo hace). Entonces puedes usar x filepara correr ./file.

No intentes definir un .comando. El comando . scriptya se ejecuta scripten el shell actual. Esto permite scriptdefinir variables de entorno para el shell actual.

sourcejedi
fuente
3
Creo que puede haber una buena sugerencia aquí, pero no hay explicación de lo que esto hace. Podría resolverlo, pero un usuario inexperto no tendría ninguna posibilidad.
IMSoP
No hay necesidad de cambiar $ 1. Justo exec "$@".
reinierpost
$ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found
sourcejedi
(1) No hay necesidad de hacerlo shift $1; acaba exec ./"$@". (2) Dado que está hablando de un script de shell, es un poco inútil / engañoso aconsejar a las personas que no definan un .comando, ya que es imposible crear un archivo llamado .. (Es posible, y muy desaconsejable, definir un alias o función de shell llamada .).
Scott,
1

Si se nos permite hacer scripts de ayuda, puede hacer un ayudante que agregue el pwd a la RUTA, luego ejecute

. pathhelper    #adds pwd to path
file            #now it can be run without ./

Esto evita agregar "." a la ruta y contaminar su .profile con cada ruta en la que en algún momento desee ejecutar algo.

Podemos llevar este enfoque un paso más allá al crear un asistente que inicie un nuevo shell con una RUTA modificada. Si toma un directorio como parámetro (usando pwd como predeterminado), funcionaría como un pushdque edita la ruta. Es posible que tenga que tener en cuenta que cualquier cambio en otras variables de entorno se perdería al salir de la subshell, pero en un shell de larga ejecución, su variable PATH no se saturará. Dependiendo de sus flujos de trabajo, esto podría ser ventajoso.

:outer shell prompt$; subshellpathhelper    # launches a subshell with modified PATH
: subshell prompt $ ; file                  # in the subshell it can be run without ./

Pero supongo que si quería correr con ella se podía cortar pushdy popdpara que puedan realizar las mismas modificaciones a la ruta sin sin hacer un subnivel que perderá otros cambios.

pushd --path ~/some/path/    # normal pushd plus adds target to path
file                         # it can be run without ./ until you popd

(No puede hacer lo mismo cdporque no tiene un análogo popd).

También puede hacer un par de ayudantes dedicados para simplemente empujar y hacer estallar las entradas de RUTA. Lo que funciona mejor realmente depende de sus patrones de uso.

ShadSterling
fuente
En realidad, podría hacer algo así cd, pero está más allá: haga un archivo como .dircmdsy piratee cdpara que los comandos definidos ./.dircmdsno estén disponibles justo antes de cambiar y estén disponibles justo después de cambiar.
ShadSterling
-1

Puede usar la . script.shsintaxis siempre que el script que desee ejecutar esté en el directorio actual.

También puede prefijar con el intérprete, como sh o bash. ejemplo:bash script.sh

UltimateByte
fuente
8
. script.shse romperá si el script contiene exit, tiene efectos inesperados, por ejemplo, si redefinió PATH "temporalmente"; también solo funciona para scripts para su shell actual
sourcejedi
@sourcejedi Con respecto a exitque podría ponerlo entre paréntesis, es decir, un subshell, pero cierto, todavía sería solo para scripts en el mismo shell.
phk
La pregunta dice "un archivo ejecutable". Estos no funcionarán para un ejecutable binario; solo para un guión. Y tu segundo párrafo duplica la respuesta de Zanna .
Scott
Bueno, mi mal, principalmente ejecuto y desarrollo cosas de bash, así que asumí que estábamos hablando de scripts de bash :)
UltimateByte
No solo para un script, sino solo para un script Bash.
Oskar Skog