Exécuter en tant que .test plutôt que ./test

26

En supposant que je suis dans le même dossier qu'un fichier exécutable, je devrais taper ceci pour l'exécuter:

./file

Je préfère ne pas avoir à taper /, car il /m'est difficile de taper.

Existe-t-il un moyen plus simple d'exécuter un fichier? Idéalement, juste une syntaxe simple comme:

.file

ou autre chose mais plus facile que d'y insérer le /caractère.

Il y a peut-être un moyen de mettre quelque chose dans le /binrépertoire, ou de créer un alias pour l'interpréteur, afin que je puisse utiliser:

p file
IMSoP
la source
9
Peut-être échanger / avec une autre clé en utilisant xmodmap? Donc, au moins, il est plus facile de taper
Guy
26
En remarque, /est largement utilisé sous Unix, principalement comme séparateur de répertoires. Vous feriez probablement mieux de trouver un moyen plus simple de le taper.
chrylis -en grève-
7
@RossPresser Cette question n'a pas beaucoup de sens depuis. et ./ au début du fichier sont deux significations complètement différentes pour des raisons techniques que tout débutant doit connaître. /n'est pas difficile à taper pour la grande majorité des gens, et si OP a une blessure qui l'empêche, ils devraient envisager d'autres dispositions de clavier, car il n'y a aucun moyen qu'ils puissent éviter /complètement lorsqu'ils sont dans le terminal.
JFA
1
@JFA La majorité des dispositions de clavier utilisées en Europe continentale ainsi qu'en Amérique du Sud utilisent /le shift-7 qui est relativement difficile à taper, même sans blessure.
nitro2k01
6
Modifier l'historique: " pourquoi ne pouvez-vous pas simplement demander à l'interface réseau de faire toutes les requêtes Internet via un hôte distant via ssh sur le port 22. " ಠ_ಠ
Derek 朕 會 功夫

Réponses:

35

Cela peut être "risqué", mais vous pourriez en avoir. dans votre CHEMIN.

Comme cela a été dit dans d'autres, cela peut être dangereux, alors assurez-vous toujours. est à la fin du CHEMIN plutôt qu'au début.

HaloJones
la source
1
Je ne vois pas vraiment comment c'est "risqué": mon chemin a été ainsi depuis bien avant Linux, et il n'a jamais causé le moindre problème.
jamesqf
21
@jamesqf C'est risqué parce que si vous accédez cdà un répertoire accessible en écriture et essayez d'utiliser une commande qui n'est pas sur votre chemin, vous pouvez exécuter un exécutable (éventuellement malveillant) du même nom que quelqu'un a écrit sur ce chemin. C'est bien pire si vous mettez .au début de votre chemin. Dans ce cas, un exécutable malveillant appelé lsserait exécuté si vous essayez d'appeler lsdans ce répertoire.
bytesized
2
Veuillez éviter cela, pour les raisons indiquées ci-dessus. La pcommande serait meilleure.
Guido
11
@jamesqf Quand c'est "votre" système, et que vous seul l'utilisez, ce n'est pas si mal. Le problème vient (et a déclenché de nombreux administrateurs Unix au fil des ans) sur un système multi-utilisateurs. Avec un .début de PATH, tout ce qu'un utilisateur malveillant doit faire est de déposer une fausse lscommande dans son répertoire et de persuader l'administrateur de "regarder quelque chose de bizarre" et il a un accès root.
TripeHound
1
Bonne solution, même si cela ne fonctionnera pas si le fichier est nommé test, comme dans le titre de la question (car il tests'agit d'un shell intégré, et existe probablement aussi quelque part dans votre $PATHdéjà).
yellowantphil
71

.se complétera automatiquement pour./ (taper .et appuyer Tab) au moins dans les shells Bash modernes, donc vous ne devriez pas avoir à utiliser une PATHsolution complexe ou non sécurisée (comme une modification).

S'il ne se complète pas automatiquement, vous devrez peut-être installer le package "bash-complètement".

l0b0
la source
Êtes-vous sûr? .a plusieurs candidats à l'achèvement: .( répertoire actuel), (répertoire ..parent), la .commande (pour laquelle bash fournit un alias non standard source) et tout fichier dot présent. Peut-être que le bash-completionpaquet ignore cela; Je le trouve atrocement ennuyeux (par exemple, il est impossible de compléter les noms de répertoires par tabulation dans une makeligne de commande et est généralement horrible avec des makefiles remplis de règles implicites), donc je le purge toujours.
R ..
3
Je l'ai essayé, et oui, il se complète automatiquement de cette façon. Dans presque tous les cas, c'est ce qu'un utilisateur normal voudrait: je ne pense pas avoir déjà vu un fichier dot qui devrait être exécutable, exécuter quelque chose dans un sous-répertoire est beaucoup plus courant que d'exécuter quelque chose dans un répertoire parent, et IMO il le fait un sacré bon travail pour trouver des makecibles.
l0b0
Avec bash 3.2, il ne se remplit pas automatiquement. Serait-ce nouveau dans bash 4?
Calimo
2
@Calimo Plus probablement nouveau dans les versions récentes de bash-complétion. C'est loin d'être un changement fondamental.
l0b0
42

ou .. peut-être en donnant à l'interprète un alias dans le fichier bashrc, puis simplement

   p  file

Il est possible d'écrire une telle fonction:

p() {
 ./"$@"
}

dans votre ~/.bashrc. Ensuite, vous pourrez exécuter p app argumentsau lieu de ./app arguments. Cette solution fonctionne pour les exécutables de tout type, y compris les scripts et les binaires.

"$@"se développe en une liste d'arguments correctement citée passée à la fonction (en préservant tous les caractères spéciaux de l'expansion glob ou variable) et, comme l'a souligné @Scott, bashest assez intelligent pour ajouter ./le premier d'entre eux, en préservant le reste.

aitap
la source
Bien qu'il soit moins général d'exécuter l'application sous une autre commande, comme strace -f p apppour voir les appels système effectués ou $(which time) p apppour voir combien de temps cela prend. pcomme un script exécutable fonctionnerait mieux dans ces deux exemples spécifiques que j'ai inventés. Aucune des deux solutions ne pourrait fonctionner ldd p app, même si ldd elle diffère également par la nécessité d'un chemin complet, peut-être pour des raisons comme celle-ci.
sourcejedi
Oui, le remplacer p app argspar ./app argsune manière invisible pour quiconque nécessiterait une entrée de shell de tuyauterie via une sorte de préprocesseur et provoquerait toutes sortes de divertissements lorsque la substitution se produit dans un endroit non
prévu
1
Dans ce cas, ne devrait-il pas y avoir de guillemets $@? Sinon, il passera juste un gros argument au programme.
Kroltan
7
@Kroltan No. $@est un tableau. Une fois développé à l'intérieur ", chaque paramètre se développe en un mot distinct. $*se comporte comme vous le pensez.
8bittree
3
Je crois que vous avez rendu cela inutilement complexe, et c'est p() { ./"$@"; }tout ce dont vous avez besoin.
Scott
11

Vous pouvez mettre .à votre $PATHen ajoutant par exemple PATH=$PATH:.à votre /etc/profile, de cette façon, vous pouvez exécuter filesimplement en écrivant file, sauf s'il se trouve dans un autre dossier de votre chemin (par exemple /usr/bin/). Notez que ce n'est généralement pas une bonne idée.

Pourquoi c'est mauvais: disons que vous êtes dans une situation où vous ne faites pas entièrement confiance au contenu d'un répertoire - vous l'avez téléchargé depuis un endroit louche et vous voulez l'examiner avant de l'exécuter, ou vous êtes un administrateur système aidant certains l'utilisateur en regardant dans son répertoire personnel, etc. Vous voulez lister le répertoire, donc vous essayez de taper ls, mais oups, vous faites une faute de frappe, et vous avez fini par taper sl à la place. L'auteur de ce répertoire malveillant a anticipé cela et y a mis un script shell appelé "sl" qui exécute 'rm -rf --no-preserve-root /' (ou quelque chose de plus malveillant comme l'installation d'un rootkit).

(Merci @Muzer pour l'explication)

phk
la source
13
Bien que je sois entièrement d'accord, c'est probablement qui explique exactement pourquoi ce n'est pas une bonne idée.
ymbirtt
16
Pourquoi c'est mauvais: disons que vous êtes dans une situation où vous ne faites pas entièrement confiance au contenu d'un répertoire - vous l'avez téléchargé depuis un endroit louche et vous voulez l'examiner avant de l'exécuter, ou vous êtes un administrateur système aidant certains l'utilisateur en regardant dans son répertoire personnel, etc. Vous voulez lister le répertoire, donc vous essayez de taper ls, mais oups, vous faites une faute de frappe, et vous avez fini par taper sl à la place. L'auteur de ce répertoire malveillant a anticipé cela et y a mis un script shell appelé "sl" qui exécute 'rm -rf --no-preserve-root /' (ou quelque chose de plus malveillant comme l'installation d'un rootkit).
Muzer
2
Il vaut la peine d'expliquer que si le répertoire actuel est au début de $ PATH, l'attaquant pourrait simplement remplacer ls ou d'autres commandes courantes
Délisson Junio
Chapeaux de papier d' aluminium @Muzer Huuuge ici.
Sombrero Chicken
4
@GillBates C'est le genre de chose dont vous devez vous méfier en tant qu'administrateur système qui doit gérer des utilisateurs réels et potentiellement malveillants, ou quelqu'un qui analyse des archives suspectes pour gagner sa vie. Si aucun de ces éléments ne s'applique, je suis d'accord avec vous. Je ne pense toujours pas que ce soit une bonne habitude de prendre, cependant, parce que vous ne savez jamais quand votre situation va changer, vous obtenez un de ces emplois, et vous vous maudirez sans cesse pour vous être entraîné à vous fier à un comportement précaire; )
Muzer
10

Vous pouvez appeler l'interprète, par exemple

bash test

Dans ce cas, le script s'exécutera même s'il n'a ni ligne de shebang (par exemple #!/bin/bash) ni bit exécutable. Vous devrez également connaître l'interprète approprié pour l'exécuter également. Vous pouvez d'abord lire la ligne shebang du fichier pour vous assurer d'appeler l'interprète correct, par exemple si la ligne shebang indique

#!/usr/bin/env python3

tu appellerais

python3 test
Zanna
la source
7
interprète interprète juste le code, ils n'exécuteront pas les fichiers binaires
Mc Kernel
Cette réponse est quelque peu logique car peut-être que l'interpréteur peut recevoir un alias dans le fichier bashrc.
5
@McKernel bon point, cela ne fonctionne que s'il y a un interpréteur, pas pour les exécutables compilés
Zanna
2
il y a un interprète pour les exécutables compilés:/lib/ld.so
Dmitry Kudriavtsev
7

Pour autant que je sache, il n'y a aucun moyen d'y parvenir à moins d'inclure le fichier dans le chemin env, vous pouvez donc l'exécuter en tapant simplement: file

.filene fonctionnera pas car il s'agit d'un nom de fichier différent. C'est un fichier appelé.file et non ./file.

J'ai l'impression que la barre oblique peut être difficile à taper pour vous car la mise en page n'est pas en anglais, peut-être? Dans ce cas, cela m'arrive aussi, donc j'échange fréquemment ma disposition de clavier en anglais en appuyant sur Alt + Maj dans Windows (j'utilise Linux de ssh)

Mc Kernel
la source
7

Les gens ont suggéré d'ajouter .à PATH, ce qui est dangereux car cela crée un risque que vous exécutiez accidentellement un programme malveillant planté dans un répertoire accessible en écriture. Mais, si vous avez des programmes exécutables dans quelques répertoires que vous possédez et qui sont inscriptibles que par vous, alors il est sûr (assez sûr?) Pour mettre les directeur (s) dans PATH, en ajoutant une ligne comme

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

à votre ~/.bashrcdossier. Bien sûr, cela signifie que vous pouvez exécuter un programme à partir de l'un de ces répertoires depuis n'importe où dans le système de fichiers. Par exemple, vous pourriez cd /etcet tapez foo, et il s'exécuterait ~/dev/myprog1/foo. Cela présente l'inconvénient mineur que vous ne pouvez pas avoir de programmes du même nom dans plus d'un des répertoires. Plus précisément, si vous avez des programmes appelés foo dans les deux ~/dev/myprog1et ~/dev/myprog2, vous ne pourrez pas exécuter le second sauf en spécifiant un chemin. De même, si vous avez un ~/dev/myprog1/cat- mais pourquoi voudriez-vous?


Une autre approche, si vous n'avez que quelques programmes avec lesquels vous le faites, consiste à leur définir des alias:

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

Ou vous pouvez appeler les alias .gizmoet .gonzo si vous trouvez cela plus intuitif.

En fait, cela a, dans une certaine mesure, le même risque de sécurité que de mettre .dans votre PATH. Si un utilisateur malveillant peut lire votre .bashrcfichier et voir vos alias, il peut placer des logiciels malveillants appelés gizmoet gonzodans des répertoires aléatoires dans l'espoir que vous les exécuterez. Il vaut mieux utiliser ces noms de chemin absolus:

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

Soit dit en passant, vous devez éviter de nommer un exécutable test, car il s'agit d'une commande intégrée au shell, et vous ne pouvez exécuter un programme avec ce nom qu'en spécifiant un chemin ou une autre astuce.

G-Man dit «Réintègre Monica»
la source
Alternativement, vous pouvez faire une recette (si vous utilisez des Makefiles) et faire make gizmoou make gonzo.
ihato
Je suis désolé, mais je ne suis pas sûr de comprendre comment cela se rapporte à la question ou à ma réponse. Suggérez-vous que l'OP crée un Makefiledans chaque répertoire, de sorte que les actions se make gizmoterminent par l' exécution gizmo ? (1) Cela semble être une manière maladroite de faire la même chose que la pfonction, suggérée dans la question, initialement mise en œuvre par aitap , et affinée par Scott. (2) Pouvez-vous transmettre des arguments de cette façon? ISTM make gizmo arg1 arg2équivalent à make gizmo; make arg1; make arg2.
G-Man dit `` Réintègre Monica '' le
1
(1) Peut-être que mon hypothèse est fausse, mais il n'est pas clair pour moi que OP souhaite éviter l'utilisation ./dans tous les répertoires . Dans mon esprit, il développe quelque chose et a juste besoin d'exécuter le programme produit ./filesouvent. Je ne peux vraiment pas penser à un autre scénario où l'on aurait souvent besoin d'exécuter un fichier local et s'il ne l'exécute pas fréquemment, il ne prendrait pas la peine de poser la question (il a dit difficile pas impossible ) (2) pas vraiment mais vous pouvez passer les arguments dans la recette.
ihato
(1) Eh bien, je suppose que nous pouvons convenir que la motivation du PO et la portée de sa question ne sont pas claires. (2) Merci pour le lien.
G-Man dit `` Réintègre Monica '' le
3

Pour développer la réponse de Zanna à propos des interprètes (désolé, pas de représentant pour un commentaire): un "interprète" pour les exécutables natifs (alias fichiers ELF binaires) est le chargeur dynamique ( ld.so), mais il ne comprend généralement pas la syntaxe que vous souhaitez:

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

(également, sauf si vous créez un lien symbolique ld.sovers votre chemin, vous devez toujours écrire /s)

bacondropped
la source
Ceci est spécifique à Linux, non? Pourriez-vous s'il vous plaît expliquer cela davantage, pourquoi cela fonctionne? Je pensais que le noyau (Linux) ferait l'analyse et déciderait si et comment exécuter un binaire, c'est pour ça binfmt_misc.
phk
2
@phk Le fichier est spécifique à Linux, mais pas le concept d'un éditeur de liens / chargeur dynamique. Par exemple, FreeBSD a le sien /libexec/ld-elf.so.1. Sous Linux, ce n'est pas aussi simple que de "décider comment exécuter un binaire": binfmt_miscdétecte le format du fichier par des nombres magiques (ELF, script shebang, CIL). Après cela, le binfmt_elfgestionnaire est appelé. Il analyse les en-têtes et sections ELF; .interpla section contient le chemin du chargeur dynamique; ce chargeur est démarré par le noyau, effectue des délocalisations et passe à _start. Sur FreeBSD (pas sûr des autres), il n'y a pas de binfmt, mais le principe est +/- similaire.
bacondropped le
1
@phk explique pourquoi cela fonctionne - ld.son'a pas .interpet est lié statiquement, ce qui signifie qu'il n'a pas besoin d'un autre éditeur de liens / chargeur dynamique pour résoudre ses symboles externes et effectuer des calculs de relocalisation.
bacondropped le
ISTR Solaris a également quelque chose d'équivalent à cela.
G-Man dit «Réinstalle Monica»
3

Si nous sommes autorisés à commencer à configurer les choses

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

La plupart des distributions modernes incluent déjà ~ / .local / bin dans $ PATH (ajoutez- export PATH="$HOME/.local/bin:$PATH"les ~/.profilesi les vôtres ne le font pas). Ensuite, vous pouvez utiliser x filepour exécuter ./file.

N'essayez pas de définir une .commande. La commande . scripts'exécute déjà scriptdans le shell actuel. Cela permet scriptde définir des variables d'environnement pour le shell courant.

sourcejedi
la source
3
Je pense qu'il peut y avoir une bonne suggestion ici, mais il n'y a aucune explication de ce que tout cela fait. Je pourrais le résoudre, mais un utilisateur inexpérimenté n'aurait aucune chance.
IMSoP
Il n'est pas nécessaire de déplacer 1 $. Justement exec "$@".
reinierpost
$ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found
sourcejedi
(1) Il n'est pas nécessaire de le faire shift $1; juste exec ./"$@". (2) Puisque vous parlez d'un script shell, il est un peu inutile / trompeur de conseiller aux gens de ne pas définir de .commande, car il est impossible de créer un fichier appelé .. (Il est possible, et très déconseillé, de définir un alias ou une fonction shell appelée ..)
Scott
1

Si nous sommes autorisés à créer des scripts d'aide, vous pouvez créer un assistant qui ajoute le pwd au PATH, puis exécuter

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

Cela évite d'ajouter "." vers le chemin et polluer votre .profile avec chaque chemin dans lequel vous pourriez à un moment donné vouloir exécuter quelque chose.

Nous pouvons pousser cette approche un peu plus loin en créant un assistant qui lance un nouveau shell avec un PATH modifié. S'il prend un répertoire comme paramètre (en utilisant le pwd par défaut), il fonctionnerait comme un pushdqui modifie le chemin. Vous devrez peut-être garder à l'esprit que toute modification des autres variables d'environnement serait perdue lors de la fermeture du sous-shell, mais dans un shell de longue durée, votre variable PATH ne sera pas encombrée. Selon vos workflows, cela peut être avantageux.

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

Mais je suppose que si vous vouliez l'exécuter, vous pourriez pirater pushdet popdainsi ils pourraient apporter les mêmes modifications au chemin sans faire un sous-shell qui perdrait d'autres changements.

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

(Vous ne pouvez pas faire de même avec cdcar il n'a pas d'analoguepopd .)

Vous pouvez également créer une paire dédiée d'aides pour simplement pousser et faire apparaître les entrées PATH. Ce qui fonctionne le mieux dépend vraiment de vos habitudes d'utilisation.

ShadSterling
la source
En fait, vous pouvez faire quelque chose comme ça dans cd, mais c'est plus loin: créer un fichier comme .dircmds, et pirater cdpour rendre les commandes définies ./.dircmdsindisponibles juste avant le changement et disponibles juste après le changement.
ShadSterling
-1

Vous pouvez utiliser . script.sh syntaxe tant que le script que vous souhaitez exécuter se trouve dans le répertoire courant.

Vous pouvez également préfixer l'interpréteur, comme sh ou bash. Exemple:bash script.sh

UltimateByte
la source
8
. script.shse cassera si le script contient exit, a des effets inattendus, par exemple s'il a redéfini PATH "temporairement"; cela ne fonctionne également que pour les scripts de votre shell actuel
sourcejedi
@sourcejedi Concernant exitvous pourriez le mettre entre parenthèses, c'est-à-dire un sous-shell, mais c'est vrai, ce ne serait toujours que pour les scripts dans le même shell.
phk
La question dit «un fichier exécutable». Ceux-ci ne fonctionneront pas pour un exécutable binaire; uniquement pour un script. Et votre deuxième paragraphe reproduit la réponse de Zanna .
Scott
Eh bien, mon mauvais, j'exécute principalement et je développe des trucs bash, donc j'ai supposé que nous parlions de scripts bash :)
UltimateByte
Pas seulement pour un script, mais uniquement pour un script Bash.
Oskar Skog