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
, come potrei farlo per visualizzare il messaggio "You run running runme.sh" senza codificarlo?
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
, come potrei farlo per visualizzare il messaggio "You run running runme.sh" senza codificarlo?
Risposte:
me=`basename "$0"`
Per leggere un link simbolico 1 , 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, 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 collegamenti simbolici con nomi diversi è quello di fornire funzionalità diverse in base al nome che si chiama come (pensa gzip e gunzip su alcune piattaforme).
1 Cioè, per risolvere i collegamenti simbolici in modo tale che quando l'utente esegue foo.sh
un collegamento simbolico bar.sh
, si desidera utilizzare il nome risolto bar.sh
anziché foo.sh
.
$0
nel primo esempio è soggetto alla divisione di parole, 3. $0
viene passato a basename, readlink ed eco in una posizione che gli consente di essere trattato come un interruttore della riga di comando . Suggerisco invece me=$(basename -- "$0")
o in modo più efficiente a spese della leggibilità, me=${0##*/}
. Per i link simbolici, me=$(basename -- "$(readlink -f -- "$0")")
supponendo gnu utils, altrimenti sarà uno script molto lungo che non scriverò qui.
# ------------- SCRIPT ------------- # # ------------- CHIAMATO ------ ------- #
#!/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
# Nota sulla riga successiva, il primo argomento viene chiamato tra virgolette doppie, # e singole, poiché contiene due parole
$ / misc / shell_scripts / check_root / show_parms . sh "'ciao lì'" "'william'"
# ------------- RISULTATI ------------- #
# argomenti chiamati con ---> 'ciao a tutti' 'william' # $ 1 ----------------------> 'ciao a tutti' # $ 2 ---- ------------------> 'william' # percorso per me --------------> / misc / shell_scripts / check_root / show_parms. sh # percorso principale -------------> / misc / shell_scripts / check_root # my name -----------------> show_parms.sh
# ------------- FINE ------------- #
show_params
il nome senza estensione opzionale?
${0##*/}
. Testato usando GitBash.
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"
dirname $BASE_SOURCE
" per ottenere la directory in cui si trovano gli script.
$BASH_SOURCE
fornisce la risposta corretta durante l'approvvigionamento dello script.
Ciò include tuttavia il percorso, quindi per ottenere solo il nome file degli script, utilizzare:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
darebbe il nome della shell del chiamante. Beh, almeno su OSX di sicuro.
Se il nome dello script ha spazi in esso, un modo più robusto è quello di utilizzare "$0"
o "$(basename "$0")"
- o su MacOS: "$(basename \"$0\")"
. Ciò impedisce che il nome venga alterato o interpretato in alcun modo. In generale, è buona norma citare sempre due volte i nomi delle variabili nella shell.
Per rispondere a Chris Conway , su Linux (almeno) faresti 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 gli dice di non stampare una nuova riga. -f gli dice di seguire completamente il link (se un link simbolico fosse un link ad un altro link, lo risolverebbe anche quello).
Ho trovato che questa linea funziona sempre, indipendentemente dal fatto che il file provenga o venga eseguito come script.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Se si desidera seguire i collegamenti simbolici, utilizzare readlink
il percorso sopra riportato, in modo ricorsivo o non ricorsivo.
Il motivo per cui il one-liner funziona è spiegato dall'uso della BASH_SOURCE
variabile d'ambiente 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 shell corrispondenti nella variabile di matrice FUNCNAME. La funzione shell $ {FUNCNAME [$ i]} è definita nel file $ {BASH_SOURCE [$ i]} e chiamata da $ {BASH_SOURCE [$ i + 1]}.
FUNCNAME
Una variabile di matrice contenente i nomi di tutte le funzioni della shell attualmente nello stack delle 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 alcun 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 chiamante incorporato visualizza lo stack di chiamate corrente utilizzando queste informazioni.
[Fonte: manuale di Bash]
a
(supponi che a
il contenuto sia echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) da una sessione interattiva - quindi ti darà a
il percorso. Ma se scrivi uno script b
con source a
dentro ed esegui ./b
, ritornerà b
il percorso.
Queste risposte sono corrette per i casi che indicano, 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 dello script stesso.
Questo è un caso limite e non dovrebbe essere preso TROPPO sul serio. Se esegui lo script direttamente da un altro script (senza "sorgente"), l'utilizzo di $ 0 funzionerà.
Poiché alcuni commenti hanno chiesto il nome del file senza estensione, ecco un esempio su come farlo:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Godere!
Ri: Risposta di Tanktalus (accettata) sopra, un modo leggermente più pulito è usare:
me=$(readlink --canonicalize --no-newline $0)
Se il tuo script proviene da un altro script bash, puoi utilizzare:
me=$(readlink --canonicalize --no-newline $BASH_SOURCE)
Concordo sul fatto che sarebbe difficile confondere i link simbolici se il tuo obiettivo è fornire feedback all'utente, ma ci sono occasioni in cui è necessario ottenere il nome canonico in uno script o in un altro file, e questo è il modo migliore, imo.
source
nomi degli script.
se il tuo invocare lo script shell piace
/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"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Questo risolve i collegamenti simbolici (realpath lo fa), gestisce gli spazi (le doppie virgolette lo fanno) e troverà il nome corrente dello script anche quando è di provenienza (. ./Myscript) o chiamato da altri script ($ BASH_SOURCE lo gestisce). Dopotutto, è bene salvarlo in una variabile d'ambiente per riutilizzarlo o per copiarlo altrove (this =) ...
realpath
non è un comando BASH integrato. È un eseguibile autonomo disponibile solo in alcune distribuzioni
In bash
è possibile ottenere il nome del file di script utilizzando $0
. In genere $1
, $2
ecc. Devono accedere agli argomenti della CLI. Allo stesso modo $0
è accedere al nome che attiva lo script (nome del file di script).
#!/bin/bash
echo "You are running $0"
...
...
Se invochi lo script con percorso come /path/to/script.sh
allora, $0
anche il nome file con percorso verrà assegnato. In tal caso è necessario utilizzare $(basename $0)
per ottenere solo il nome del file di script.
$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 ./linktoscript
stampa script.sh
?
[EDIT] Per @ephemient nei commenti sopra, sebbene la cosa del collegamento simbolico possa sembrare inventata, è possibile giocherellare in $0
modo tale da non rappresentare una risorsa del filesystem. L'OP è un po 'ambiguo su ciò che voleva.
Informazioni 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
Breve, chiaro e semplice, in my_script.sh
#!/bin/bash
running_file_name=$(basename "$0")
echo "You are running '$running_file_name' file."
Produzione:
./my_script.sh
You are running 'my_script.sh' file.
DIRECTORY=$(cd `dirname $0` && pwd)
Ho ottenuto quanto sopra da un'altra domanda Stack Overflow: uno script Bash può dire in quale directory è memorizzato? , ma penso che sia utile anche per questo argomento.
Ecco cosa mi è venuto in mente, ispirato alla risposta di Dimitre Radoulov (che ho votato, comunque) .
script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"
echo "Called $script with $# argument(s)"
indipendentemente dal modo in cui chiami la tua sceneggiatura
. path/to/script.sh
o
./path/to/script.sh
qualcosa del genere?
export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh
#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size
echo "Would you like to empty Trash [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
return $TRUE
}
#-----------------------------------------------------------------------
start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www open a homepage "
echo "htest trash empty trash "
return $TRUE
} #end Help
#-----------------------------------------------#
homepage=""
return $TRUE
} #end cpdebtemp
# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
val="*** Unknown ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
val=$1
fi
# use case statement to make decision for rental
case $val in
"trash") start_trash ;;
"help") start_help ;;
"www") firefox $homepage ;;
*) echo "Sorry, I can not get a $val for you!";;
esac
# Case stop