Eseguire come .test anziché ./test


26

Supponendo che io sia nella stessa cartella di un file eseguibile, dovrei digitare questo per eseguirlo:

./file

Preferirei non dover scrivere /, perché /è difficile per me scrivere.

C'è un modo più semplice per eseguire un file? Idealmente solo una semplice sintassi come:

.file

o qualcos'altro ma più facile che dover inserire il /personaggio lì.

Forse c'è un modo per mettere qualcosa nella /bindirectory o creare un alias per l'interprete, in modo che io possa usare:

p file

9
Forse scambiare / con un'altra chiave usando xmodmap? Quindi almeno è più facile da scrivere
Guy

26
Come nota a margine, /viene ampiamente utilizzato in Unix, in gran parte come separatore di directory. Probabilmente stai meglio trovare un modo più semplice per digitarlo.
Chrylis

7
@RossPresser Questa domanda ha poco senso da allora. e ./ all'inizio del file sono due significati completamente diversi per ragioni tecniche che ogni principiante dovrebbe conoscere. /non è difficile da digitare per la stragrande maggioranza delle persone, e se OP ha un infortunio che lo impedisce, dovrebbero prendere in considerazione layout di tastiera alternativi, poiché non è possibile evitare /completamente quando si trovano nel terminale.
JFA,

1
@JFA La maggior parte dei layout di tastiera utilizzati nell'Europa continentale e in Sud America utilizza /Shift-7, che è relativamente difficile da scrivere, anche senza infortuni.
nitro2k01,

6
Modifica cronologia: " perché non è possibile istruire semplicemente l'interfaccia di rete a effettuare tutte le query Internet tramite un host remoto tramite SSH sulla porta 22. " ಠ_ಠ
Derek 朕 會 功夫

Risposte:


35

Può essere "rischioso" ma potresti semplicemente averlo. nel tuo PERCORSO.

Come è stato detto in altri, questo può essere pericoloso, quindi assicurati sempre. è alla fine del PERCORSO piuttosto che all'inizio.


1
Non vedo come sia "rischioso": il mio percorso è stato così da molto prima di Linux, e non ha mai causato il minimo problema.
jamesqf,

21
@jamesqf È rischioso perché se si accede cda una directory che è scrivibile in tutto il mondo e si tenta di utilizzare un comando che non si trova sul proprio percorso, è possibile eseguire un eseguibile (possibilmente dannoso) con lo stesso nome che qualcuno ha scritto in quel percorso. Questo è molto peggio se lo metti .all'inizio del tuo percorso. In tal caso, un eseguibile dannoso chiamato lsverrebbe eseguito se si tenta di chiamare lsin quella directory.
Bytesized

2
Si prega di evitare questo, per i motivi sopra indicati. Il pcomando sarebbe migliore.
Guido

11
@jamesqf Quando è il "tuo" sistema, e solo tu lo usi, non è poi così male. Il problema si presenta (e ha fatto inciampare molti amministratori Unix nel corso degli anni) sul sistema multiutente. Con un .inizio PATH, tutto ciò che un utente malintenzionato deve fare è rilasciare un lscomando falso nella loro directory e convincere l'amministratore a "guardare qualcosa di strano" e hanno accesso root.
TripeHound,

1
Buona soluzione, anche se non funzionerà se il file viene chiamato test, come nel titolo della domanda (poiché testè una shell integrata e probabilmente esiste $PATHgià da qualche parte nel tuo ).
Yellowantphil,

71

.si completerà automaticamente per./ (digitare .e premere Tab) almeno nelle moderne shell Bash, quindi non dovresti usare una soluzione complessa o insicura (come la PATHmodifica).

Se non si completa automaticamente, potrebbe essere necessario installare il pacchetto "bash-completamento".


Sei sicuro? .ha più candidati per il completamento: .(dir corrente), ..(dir parent), il .comando (per cui bash fornisce un alias non standard source) e tutti i dotfile presenti. Forse il bash-completionpacchetto lo ignora; Lo trovo atrocemente fastidioso (ad esempio, rende impossibile completare i nomi delle directory in una makeriga di comando ed è generalmente terribile con i makefile pieni di regole implicite) quindi lo elimino sempre.
R ..

3
L'ho provato e sì, si completa automaticamente in questo modo. In quasi tutti i casi è quello che vorrebbe un utente normale: non credo di aver mai visto un dotfile che dovrebbe essere eseguibile, eseguire qualcosa in una sottodirectory è molto più comune che eseguire qualcosa in una directory padre, e IMO lo fa un dannato buon lavoro nel trovare makeobiettivi.
l0b0

Con bash 3.2 non si completa automaticamente. Potrebbe essere nuovo in Bash 4?
Calimo,

2
@Calimo Più probabilmente nuovo nelle recenti versioni di bash-completamento. È tutt'altro che un cambiamento fondamentale.
l0b0

42

o .. forse dare all'interprete un alias nel file bashrc e poi semplicemente

   p  file

È possibile scrivere una tale funzione:

p() {
 ./"$@"
}

nel tuo ~/.bashrc. Quindi sarai in grado di eseguire p app argumentsinvece di ./app arguments. Questa soluzione funziona per eseguibili di qualsiasi tipo, inclusi script e binari.

"$@"si espande in un elenco di argomenti opportunamente citato passato alla funzione (preservando tutti i caratteri speciali dall'espansione globale o variabile) e, come sottolineato da @Scott, bashè abbastanza intelligente da anteporre ./al primo di essi, preservando il resto.


Anche se è meno generale per l'esecuzione dell'app con un altro comando, ad esempio strace -f p appvedere le chiamate di sistema effettuate o $(which time) p appvedere quanto tempo impiega. pcome script eseguibile avrebbe funzionato meglio in questi due esempi specifici che ho ideato. Nessuna soluzione può funzionare ldd p app, sebbene differisca ldd anche nel richiedere un percorso completo, forse per ragioni come questa.
sourcejedi,

Sì, sostituendo p app argscon ./app argsin un modo che è invisibile a chiunque richiederebbe tubazioni di ingresso guscio attraverso un qualche tipo di preprocessore e causerebbe ogni sorta di divertimento quando si verifica la sostituzione in un luogo non volute :)
aitap

1
In questo caso, non dovrebbero esserci citazioni in giro $@? Altrimenti passerà solo un grande argomento al programma.
Kroltan,

7
@Kroltan No. $@è un array. Se espanso all'interno ", ogni parametro si espande in una parola separata. $*si comporta come stai pensando.
8bittree,

3
Credo che tu l'abbia reso inutilmente complesso, e questo p() { ./"$@"; }è tutto ciò di cui hai bisogno.
Scott,

11

Potresti metterti .al tuo $PATHaggiungendo ad esempio PATH=$PATH:.al tuo /etc/profile, in questo modo puoi eseguire filesemplicemente scrivendo file, a meno che non sia in qualche altra cartella nel tuo percorso (ad esempio /usr/bin/). Si noti che questa non è generalmente una buona idea.

Perché è brutto: supponi di trovarti in una situazione in cui non ti fidi completamente del contenuto di una directory: l'hai scaricato da qualche parte malvagio e vuoi investigarlo prima di eseguirlo, oppure sei un amministratore di sistema che aiuta alcuni guardando la loro home directory, ecc. Si desidera elencare la directory, quindi si tenta di digitare ls, ma oops, si fa un errore di battitura e si è finito invece a digitare sl. L'autore di questa directory dannosa lo ha anticipato e ha inserito uno script shell chiamato "sl" che esegue 'rm -rf --no-preserv-root /' (o qualcosa di più dannoso come l'installazione di un rootkit).

(Grazie @Muzer per la spiegazione)


13
Anche se concordo pienamente, probabilmente spiegherà esattamente perché questa non è una buona idea.
ymbirtt

16
Perché è brutto: supponi di trovarti in una situazione in cui non ti fidi completamente del contenuto di una directory: l'hai scaricato da qualche parte malvagio e vuoi investigarlo prima di eseguirlo, oppure sei un amministratore di sistema che aiuta alcuni guardando la loro home directory, ecc. Si desidera elencare la directory, quindi si tenta di digitare ls, ma oops, si fa un errore di battitura e si è finito invece a digitare sl. L'autore di questa directory dannosa lo ha anticipato e ha inserito uno script shell chiamato "sl" che esegue 'rm -rf --no-preserv-root /' (o qualcosa di più dannoso come l'installazione di un rootkit).
Muzer,

2
Vale la pena spiegare che se la directory corrente è all'inizio di $ PATH, invece, l'attaccante potrebbe semplicemente ignorare ls o altri comandi comuni
Délisson Junio

@Muzer Huuuge cappelli di stagnola qui.
Sombrero Chicken

4
@GillBates È il genere di cose di cui dovresti stare attento come amministratore di sistema che ha a che fare con utenti reali e potenzialmente dannosi, o qualcuno che analizza archivi sospetti per vivere. Se nessuno dei due si applica, allora sono d'accordo con te. Continuo a non pensare che sia una buona abitudine, perché non sai mai quando cambieranno le circostanze, ottieni uno di questi lavori e ti maledirai all'infinito per esserti allenato a fare affidamento su comportamenti insicuri; )
Muzer

10

Puoi chiamare l'interprete, per esempio

bash test

In questo caso, lo script verrà eseguito anche se non ha né una riga shebang (ad esempio #!/bin/bash) né un bit eseguibile. Dovrai conoscere anche l'interprete corretto per eseguirlo. Puoi leggere prima la riga shebang del file per assicurarti di chiamare l'interprete corretto, ad esempio se la riga shebang dice

#!/usr/bin/env python3

tu chiameresti

python3 test

7
l'interprete interpreta semplicemente il codice, non eseguiranno file binari
Mc Kernel

Questa risposta è in qualche modo logica perché forse all'interprete può essere dato un alias nel file bashrc.

5
@McKernel buon punto, funziona solo se c'è un interprete, non per eseguibili compilati
Zanna

2
c'è un interprete per gli eseguibili compilati:/lib/ld.so
Dmitry Kudriavtsev

7

Per quanto ne so, non c'è modo di ottenerlo se non si include il file nel percorso env, quindi è possibile eseguirlo semplicemente digitando: file

.filenon funzionerà poiché si tratta di un nome file diverso. È un file chiamato .filee non ./file.

Sento che la barra potrebbe essere difficile da digitare per te a causa del layout non inglese, forse? In quel caso, succede anche a me, quindi cambio frequentemente il layout della tastiera in inglese premendo Alt + Maiusc in Windows (utilizzo Linux da ssh)


7

La gente ha suggerito di aggiungere .a PATH, che è pericoloso perché crea un rischio che verrà eseguito accidentalmente un programma dannoso piantato in una directory scrivibile-mondo. Ma, se si dispone di programmi eseguibili in alcune directory che si possiedono e sono scrivibili solo da voi, allora è sicuro (abbastanza sicuro?) Per mettere quelli direttore (i) in PATH, con l'aggiunta di una linea come

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

al tuo ~/.bashrcfile. Ovviamente questo significa che puoi eseguire un programma da una di quelle directory da qualsiasi parte del filesystem. Ad esempio, è possibile cd /etce digitare fooe verrebbe eseguito ~/dev/myprog1/foo. Ciò ha il piccolo inconveniente di non poter avere programmi con lo stesso nome in più di una directory. In particolare, se hai programmi chiamati foo in entrambi ~/dev/myprog1e ~/dev/myprog2, non sarai in grado di eseguire il secondo se non specificando un percorso. Allo stesso modo se hai un ~/dev/myprog1/cat- ma perché dovresti farlo?


Un altro approccio, se hai solo alcuni programmi con cui lo fai, è definire alias per loro:

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

Oppure puoi chiamare gli alias .gizmoe .gonzo se lo ritieni più intuitivo.

In realtà, questo ha, in una certa misura, lo stesso rischio per la sicurezza che si presenta .al tuo PATH. Se un utente malintenzionato può leggere il tuo .bashrce vedere i tuoi alias, allora potrebbe mettere malware chiamato gizmoe gonzoin directory casuali nella speranza che tu lo esegua. È meglio fare in modo che questi utilizzino nomi di percorso assoluti:

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

A proposito, dovresti evitare di nominare un eseguibile test, perché si tratta di un comando incorporato nella shell, e puoi eseguire un programma con quel nome solo specificando un percorso o qualche altro trucco.


In alternativa puoi creare una ricetta (se usi Makefile) e fare make gizmoo make gonzo.
Ihato

Mi dispiace, ma non sono sicuro di capire come ciò si collega alla domanda o alla mia risposta. Stai suggerendo che l'OP crei un Makefilein ogni directory, in modo tale che le azioni make gizmofiniscano per essere eseguite gizmo ? (1) Sembra un modo imbarazzante di fare la stessa cosa della pfunzione, suggerito nella domanda, inizialmente implementato da Aitap e perfezionato da Scott. (2) Puoi passare argomenti in questo modo? ISTM make gizmo arg1 arg2equivalente a make gizmo; make arg1; make arg2.
G-Man dice "Ripristina Monica" il

1
(1) Forse la mia ipotesi è sbagliata ma non è chiaro per me OP vuole evitare di utilizzare ./in ogni directory . Nella mia mente, sta sviluppando qualcosa e deve solo eseguire ./filespesso il programma prodotto . Non riesco davvero a pensare a nessun altro scenario in cui uno dovrebbe spesso eseguire un file locale e se non lo esegue frequentemente non si preoccuperebbe di porre la domanda (ha detto difficile non impossibile ) (2) non proprio ma puoi passare gli argomenti nella ricetta.
Ihato

(1) Suppongo che possiamo concordare sul fatto che la motivazione del PO e la portata della sua domanda non sono chiare. (2) Grazie per il link.
G-Man dice "Ripristina Monica" il

3

Per espandere la risposta di Zanna sugli interpreti (scusate, nessun rappresentante per un commento): un "interprete" per eseguibili nativi (ovvero file binari ELF) è il caricatore dinamico ( ld.so), ma in genere non comprende la sintassi desiderata:

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

(inoltre, a meno che non ti colleghi simbolicamente ld.soal tuo percorso, dovrai comunque scrivere /s)


Questo è specifico per Linux, giusto? Potresti spiegarlo di più, perché funziona? Ho pensato che il kernel (Linux) avrebbe analizzato e deciso se e come eseguire un binario, ecco a cosa binfmt_miscserve.
phk,

2
@phk Il file è specifico di Linux, ma il concetto di un linker / caricatore dinamico non lo è. Ad esempio, FreeBSD ha il suo /libexec/ld-elf.so.1. Su Linux, non è semplice come "decidere come eseguire un binario": binfmt_miscrileva il formato del file tramite numeri magici (ELF, script shebang, CIL). Successivamente, binfmt_elfviene chiamato il gestore. Analizza le intestazioni e le sezioni ELF; .interpla sezione contiene il percorso del caricatore dinamico; questo caricatore viene avviato dal kernel, esegue i trasferimenti e passa a _start. Su FreeBSD (non sono sicuro degli altri) non c'è binfmt, ma il principio è +/- simile.
bacondropped

1
@phk sul perché questo funziona - ld.sonon ha .interped è staticamente collegato, il che significa che non è necessario che un altro linker / caricatore dinamico risolva i suoi simboli esterni e faccia matematica di rilocazione.
bacondropped

ISTR Solaris ha anche qualcosa di equivalente a questo.
G-Man dice "Reinstate Monica"

3

Se ci è permesso iniziare a configurare le cose

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

Le distribuzioni più moderne includono ~ / .local / bin in $ PATH (aggiungi export PATH="$HOME/.local/bin:$PATH"al tuo ~/.profilese il tuo non lo fa). Quindi è possibile utilizzare x fileper eseguire ./file.

Non provare a definire un .comando. Il comando è . scriptgià in esecuzione scriptnella shell corrente. Ciò consente scriptdi definire le variabili di ambiente per la shell corrente.


3
Penso che ci possa essere un buon suggerimento qui, ma non c'è spiegazione di ciò che fa tutto ciò. Potrei risolverlo, ma un utente inesperto non avrebbe alcuna possibilità.
IMSoP

Non è necessario spostare $ 1. Basta exec "$@".
reinierpost,

$ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found
FonteJedi

(1) Non è necessario shift $1; solo exec ./"$@". (2) Dato che stai parlando di uno script di shell, è un po 'inutile / fuorviante consigliare alle persone di non definire un .comando, poiché è impossibile creare un file chiamato .. (È possibile, e molto sconsigliabile, definire una funzione alias o shell chiamata ..)
Scott

1

Se ci è permesso creare script di supporto, potresti creare un supporto che aggiunge il pwd al PERCORSO, quindi esegui

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

Questo evita di aggiungere "." al percorso e inquinando il tuo .profile con ogni percorso in cui potresti voler eseguire qualcosa.

Possiamo fare un ulteriore passo avanti con questo approccio creando un helper che lancia una nuova shell con un PATH modificato. Se accetta una directory come parametro (usando pwd come predefinito), funzionerebbe come una pushdmodifica del percorso. Potrebbe essere necessario tenere presente che eventuali modifiche ad altre variabili di ambiente andrebbero perse quando si esce dalla subshell, ma in una shell di lunga durata la variabile PATH non sarà ingombra. A seconda dei flussi di lavoro, questo potrebbe essere vantaggioso.

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

Ma immagino che se volessi correre con esso, potresti hackerare pushde popdquindi possono apportare le stesse modifiche al percorso senza fare una subshell che perderà altre modifiche.

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

(Non puoi fare lo stesso con cdperché non ha un analogo popd.)

Puoi anche creare una coppia dedicata di helper per fare semplicemente push e pop delle voci PATH. Ciò che funziona meglio dipende davvero dai modelli di utilizzo.


In realtà, potresti fare qualcosa del genere cd, ma è più in là: crea un file simile .dircmdse scatta cdper rendere i comandi definiti ./.dircmdsnon disponibili subito prima del passaggio e disponibili subito dopo il passaggio.
ShadSterling

-1

È possibile utilizzare la . script.shsintassi fintanto che lo script che si desidera eseguire si trova nella directory corrente.

Puoi anche aggiungere un prefisso all'interprete, come sh o bash. esempio:bash script.sh


8
. script.shsi romperà se lo script contiene exit, ha effetti inattesi, ad esempio se ridefinisce il PERCORSO "temporaneamente"; funziona anche solo per gli script per la tua shell corrente
sourcejedi

@sourcejedi Per quanto riguarda la exitpossibilità di inserirlo tra parentesi, ovvero una subshell, ma vero, sarebbe comunque solo per gli script nella stessa shell.
phk,

La domanda dice "un file eseguibile". Questi non funzioneranno per un eseguibile binario; solo per una sceneggiatura. E il tuo secondo paragrafo duplica la risposta di Zanna .
Scott,

Bene, mio ​​male, eseguo principalmente e sviluppo roba bash, quindi ho pensato che stessimo parlando di script bash :)
UltimateByte

Non solo per uno script, ma solo per uno script Bash.
Oskar Skog,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.