risposta-alla-domanda-sullo-sviluppo-web-bd.com

Come faccio a sapere il nome del file di script in uno script Bash?

Come posso determinare il nome del file di script Bash all'interno dello script stesso?

Come se il mio script fosse nel file runme.sh, allora come potrei farlo visualizzare il messaggio "Stai eseguendo runme.sh" senza codificare quello?

490
Ma99uS
me=`basename "$0"`

Per leggere tramite un link simbolico, che di solito non è quello che vuoi (di solito non vuoi confondere l'utente in questo modo), prova:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

IMO, questo produrrà risultati confusi. "Ho eseguito foo.sh, ma sta dicendo che sto eseguendo bar.sh !? Deve essere un bug!" Inoltre, uno degli scopi di avere dei collegamenti simbolici con nomi diversi è di fornire funzionalità diverse in base al nome con cui è chiamato (pensate a gzip e gunzip su alcune piattaforme).

518
Tanktalus
 # ------------- SCRIPT ------------- # 

#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit

 # ---------- --- CHIAMATO ------------- # 

 # Nota sulla riga successiva, il primo argomento è chiamato tra double, 
 # E virgolette singole, poiché contiene due parole 

 $ /misc/Shell_scripts/check_root/show_parms.sh "'ciao lì'" "'' william '" 

 # --------- ---- RISULTATI ------------- # 

 # Argomenti chiamati con ---> 'ciao li' 'william' 
 # $ 1 ----- -----------------> 'ciao li' 
 # $ 2 ----------------------> 'william' 
 # percorso per me --------------> /misc/Shell_scripts/check_root/show_parms.sh
# percorso genitore --------- ----> /misc/Shell_scripts/check_root
# nome mio -----------------> show_parms.sh 

 # ----- -------- FINE ------------- #
212
Bill Hernandez

Con bash> = 3 i seguenti lavori:

$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
172
Dimitre Radoulov

Se il nome dello script contiene spazi, un modo più efficace è utilizzare "$0" o "$(basename "$0")" - o su MacOS: "$(basename \"$0\")". Ciò impedisce al nome di essere storpiato o interpretato in alcun modo. In generale, è buona norma citare sempre i nomi delle variabili in Shell.

60
Josh Lee

$BASH_SOURCE fornisce la risposta corretta durante l'individuazione dello script.

Questo tuttavia include il percorso in modo da ottenere solo il nome file degli script, utilizzare:

$(basename $BASH_SOURCE) 
58
Zainka

Se lo vuoi senza il percorso, useresti ${0##*/}

21
Mr. Muskrat

Per rispondere Chris Conway , su Linux (almeno) si dovrebbe fare questo:

echo $(basename $(readlink -nf $0))

readlink stampa il valore di un collegamento simbolico. Se non è un collegamento simbolico, stampa il nome del file. -n dice di non stampare una nuova riga. -f dice di seguire completamente il collegamento (se un link simbolico era un link ad un altro link, avrebbe risolto anche quello).

19

Ho trovato questa linea sempre funzionante, indipendentemente dal fatto che il file sia stato originato o eseguito come script.

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

Se vuoi seguire i link simbolici usa readlink sul percorso che ottieni sopra, in modo ricorsivo o non ricorsivo.

Il motivo per cui il one-liner funziona è spiegato dall'uso della variabile d'ambiente BASH_SOURCE e del suo associato FUNCNAME.

BASH_SOURCE

Una variabile di matrice i cui membri sono i nomi dei file di origine in cui sono definiti i nomi delle funzioni di shell corrispondenti nella variabile dell'array FUNCNAME. La funzione Shell $ {FUNCNAME [$ i]} è definita nel file $ {BASH_SOURCE [$ i]} e chiamata da $ {BASH_SOURCE [$ i + 1]}.

FUNCNAME

Una variabile di matrice che contiene i nomi di tutte le funzioni di Shell attualmente nello stack di chiamate di esecuzione. L'elemento con indice 0 è il nome di qualsiasi funzione Shell attualmente in esecuzione. L'elemento più in basso (quello con l'indice più alto) è "principale". Questa variabile esiste solo quando è in esecuzione una funzione Shell. Le assegnazioni a FUNCNAME non hanno effetto e restituiscono uno stato di errore. Se FUNCNAME non è impostato, perde le sue proprietà speciali, anche se viene successivamente ripristinato. 

Questa variabile può essere utilizzata con BASH_LINENO e BASH_SOURCE. Ogni elemento di FUNCNAME ha elementi corrispondenti in BASH_LINENO e BASH_SOURCE per descrivere lo stack di chiamate. Ad esempio, $ {FUNCNAME [$ i]} è stato chiamato dal file $ {BASH_SOURCE [$ i + 1]} al numero di riga $ {BASH_LINENO [$ i]}. Il built-in del chiamante visualizza lo stack di chiamate corrente utilizzando queste informazioni.

[Fonte: manuale di Bash]

13
gkb0986

Queste risposte sono corrette per i casi che dichiarano, ma c'è ancora un problema se si esegue lo script da un altro script usando la parola chiave 'source' (in modo che venga eseguito nella stessa shell). In questo caso, ottieni $ 0 dello script chiamante. E in questo caso, non credo sia possibile ottenere il nome stesso della sceneggiatura.

Questo è un caso Edge e non dovrebbe essere preso troppo sul serio. Se si esegue direttamente lo script da un altro script (senza 'source'), l'utilizzo di $ 0 funzionerà.

11
Jim Dodd

Re: risposta (accettata) di Tanktalus sopra, un modo leggermente più pulito è usare:

me=$(readlink --canonicalize --no-newline $0)

Se il tuo script è stato originato da un altro script bash, puoi usare:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)

Sono d'accordo sul fatto che confonderebbe i collegamenti simbolici di dereferenzia se il tuo obiettivo è quello di fornire un feedback all'utente, ma ci sono occasioni in cui devi ottenere il nome canonico per uno script o un altro file, e questo è il modo migliore, imo.

8
simon

Poiché alcuni commenti hanno chiesto il nome del file senza estensione, ecco un esempio su come ottenere ciò:

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}

Godere!

7
Simon Mattes

se il tuo invocare script di Shell come 

/home/mike/runme.sh

$ 0 è il nome completo

 /home/mike/runme.sh

basename $ 0 otterrà il nome del file di base

 runme.sh

e devi inserire questo nome di base in una variabile come

filename=$(basename $0)

e aggiungi il tuo testo aggiuntivo 

echo "You are running $filename"

così piacciono i tuoi script 

/home/mike/runme.sh
#!/bin/bash 
filename=$(basename $0)
echo "You are running $filename"
6
LawrenceLi
this="$(dirname "$(realpath "$BASH_SOURCE")")"

Questo risolve i collegamenti simbolici (realpath lo fa), gestisce gli spazi (le virgolette lo fanno) e troverà il nome dello script corrente anche quando è originato (./myscript) o chiamato da altri script ($ BASH_SOURCE lo gestisce). Dopotutto, è bene salvarlo in una variabile d'ambiente per riutilizzarlo o copiare facilmente altrove (this =) ...

5
jcalfee314

Puoi usare $ 0 per determinare il nome dello script (con percorso completo) - per ottenere il nome dello script solo tu puoi tagliare quella variabile con

basename $0
5
VolkA

In bash puoi ottenere il nome del file di script usando $0. Generalmente $1, $2 ecc sono per accedere agli argomenti CLI. Allo stesso modo $0 consente di accedere al nome che attiva lo script (nome del file di script).

#!/bin/bash
echo "You are running $0"
...
...

Se invochi lo script con un percorso come /path/to/script.sh allora $0 fornirà anche il nome del file con percorso. In tal caso è necessario utilizzare $(basename $0) per ottenere solo il nome del file di script.

2
rashok

Info grazie a Bill Hernandez. Ho aggiunto alcune preferenze che sto adottando.

#!/bin/bash
function Usage(){
    echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
    echo
    echo "# arguments called with ---->  ${@}     "
    echo "# \$1 ----------------------->  $1       "
    echo "# \$2 ----------------------->  $2       "
    echo "# path to me --------------->  ${0}     " | sed "s/$USER/\$USER/g"
    echo "# parent path -------------->  ${0%/*}  " | sed "s/$USER/\$USER/g"
    echo "# my name ------------------>  ${0##*/} "
    echo
}

Saluti

2
linxuser
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
                   && readlink ${BASH_SOURCE[0]} \
                   || echo ${BASH_SOURCE[0]}`")"
1
ecwpz91

Ecco cosa mi è venuto in mente, ispirato da Dimitre Radoulov 's risposta (che ho svalutato, tra l'altro).

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

indipendentemente dal modo in cui chiami il tuo script

. path/to/script.sh

o

./path/to/script.sh
0

echo "Stai eseguendo $ 0"

0
mmacaulay

$0 non risponde alla domanda (come ho capito). Una dimostrazione:

 $ cat script.sh 
 #! /bin/sh
echo `basename $ 0` 
 $ ./script.sh 
 script.sh 
 $ ln script.sh linktoscript 
 $ ./linktoscript 
 linktoscript 

Come si ottiene ./linktoscript per stampare script.sh?

[EDIT] Per @ephemient nei commenti sopra, sebbene la cosa simbolica del link possa sembrare forzata, è possibile giocare con $0 in modo tale che non rappresenti una risorsa del filesystem. L'OP è un po 'ambiguo su ciò che voleva.

0
Chris Conway
DIRECTORY=$(cd `dirname $0` && pwd)

Ho ottenuto quanto sopra da un'altra domanda di Overflow dello Stack, Uno script Bash può indicare in quale directory è memorizzato?, ma penso che sia utile anche per questo argomento.

0
Koter84