Trova la posizione dello script shell di provenienza


8

È possibile che uno script di shell di provenienza conosca la sua posizione? Ho letto la determinazione percorso script della shell di origine ma le risposte concentro su bashe tcshe non riuscire se si utilizza una shell POSIX. $0inoltre non è la soluzione e produce risultati errati .

Una soluzione non deve essere affidabile al 100%. È improbabile che il percorso contenga hard o symlink.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Alcuni retroscena: lo script fa parte di un'applicazione esistente contenente dozzine di file binari in una bindirectory in una posizione nota (varia per architettura) rispetto allo script di provenienza. Per utilizzare l'applicazione, l'utente genera lo script che antepone la bindirectory a PATH, in modo che i binari dell'applicazione possano essere facilmente richiamati nella shell corrente (qualunque shell possa essere).


Controlla una volta che questo link potrebbe essere quello che stai cercando paste.ubuntu.com/6242655
Rahul Patil

@RahulPatil Funziona solo su bash ed è altamente insostituibile.
Marco,

1
Sono abbastanza sicuro che la risposta sia no. Hai trovato solo metodi specifici della shell perché non esiste un metodo portatile. A cosa ti serve? Puoi dire agli utenti dello script di fare qualcosa di diverso da . /path/to/scriptcome MARCO_DIR=/path/to; . $MARCO_DIR/scripto eval "$(/path/to/script)"? @RahulPatil BASH_SOURCEè ovviamente specifico per bash.
Gilles 'SO- smetti di essere malvagio' il

@Gilles Come ho detto, non deve essere molto robusto. Ma non ho trovato un modo che funzioni anche in remoto nei casi più semplici in una shell POSIX. (Quindi la soluzione per ora è che l'uso di questa applicazione richiede una delle shell supportate.) Sentiti libero di pubblicare "no ..." come risposta se questa è la risposta.
Marco,

@Gilles Cambiare il modo in cui l'applicazione è impostata non è un'opzione. Si romperanno le installazioni. Ecco perché mi sarebbe piaciuto rendere lo script più robusto senza cambiare il modo in cui viene chiamato. Alla fine imposta semplicemente il PERCORSO, quindi se lo script fallisce, il fallback è trovare i binari e aggiungere il loro percorso all'ambiente.
Marco,

Risposte:


9

Il percorso dello script di provenienza non è disponibile a meno che non si stia utilizzando una shell che offre estensioni alla specifica POSIX. Puoi testarlo con il seguente frammento:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

dove included.shcontiene

echo "$0"
set

In bash, si trova il nome dello script di provenienza $BASH_SOURCE. In zsh (in modalità di compatibilità zsh, non in modalità di compatibilità sh o ksh), è in $0(si noti che in una funzione $0è invece il nome della funzione). In pdksh e dash, non è disponibile. In ksh93, questo metodo non rivela la soluzione, ma il percorso completo per lo script incluso è disponibile come ${.sh.file}.

Se richiedere bash o ksh93 o zsh è abbastanza buono, puoi usare questo snippet:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Puoi provare a indovinare la posizione dello script guardando quali file ha aperto la shell. A livello sperimentale questo sembra funzionare con dash e pdksh ma non con bash o ksh93 che almeno per un breve script hanno chiuso il file di script quando riescono a eseguirlo.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

Lo script potrebbe non essere il file con il descrittore con il numero più alto se lo script proviene da uno script complesso che ha eseguito i reindirizzamenti. Potresti voler scorrere i file aperti. Questo non è garantito per funzionare comunque. L'unico modo affidabile per individuare uno script di provenienza è utilizzare bash, ksh93 o zsh.


Se è possibile modificare l'interfaccia, quindi anziché eseguire il sourcing dello script, fare in modo che lo script stampi uno snippet di shell da trasmettere al evalchiamante. Questo è ciò che generalmente fanno gli script per impostare le variabili di ambiente. Consente di scrivere la sceneggiatura indipendentemente dai capricci della configurazione della shell e della shell del chiamante.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

Nel chiamante: eval "`/path/to/setenv`"


0

Aggiungendo alla risposta di Gilles, PUOI essere in grado di ottenere lo script della shell ( if $0 = ash) attraverso il /proc/$$ interface. Non so quanto sia preciso, ma /proc/$$/fd/11sembra puntare sempre a this_script con la cenere di BusyBox.

Fornendo questo come una potenziale risposta a coloro che si imbattono in questa pagina (come ho fatto io).

L'ultima risposta è stata eliminata, quindi la mia richiesta di questo lavoro è stata testata su 4 diverse piattaforme HW (x86, ARM, XLP e powerpc). Tutti danno la stessa risposta di fd / 11. Un readlink da /proc/$$/fd/11restituisce la mia sceneggiatura.

Andy

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.