2012-02-09 5 views
21

Dire che ho un file di script bash config.sh. È pensato per essere aggiunto ad altri script e le variabili definite vengono utilizzate come personalizzazione degli script di livello superiore.bash: definizione di una variabile file locale invisibile allo script di sourcing

Il problema è che se config.sh ha una variabile temporanea e il suo nome è in conflitto con la variabile di script di livello superiore, si interrompe quella di livello superiore.

config.sh:

TMP1=abc 
CONFIG_INPUT_DIR="$TMP1"/in 
CONFIG_OUTPUT_DIR="$TMP1"/out 

sceneggiatura di livello superiore:

TMP1=def 
source config.sh 
echo $TMP1 

Gli ultimi echo stampe abc, non def.

Soluzione 1

La mia soluzione attuale è quella di aggiungere una stringa casuale per il nome della variabile temporanea per rendere quasi impossibile al conflitto. ad esempio:

TMP1_vFc9Uiew=abc 
CONFIG_INPUT_DIR="$TMP1_vFc9Uiew"/in 
CONFIG_OUTPUT_DIR="$TMP1_vFc9Uiew"/out 
unset TMP1_vFc9Uiew 

che è doloroso e rende il codice difficile da leggere, oltre a non essere perfetto.

Soluzione 2 utilizzando local parola chiave

Dopo qualche ricerca, sono venuto a sapere local parola chiave. Ma quando dichiaro semplicemente TMP1 come local, bash si lamenta che config.sh: line 1: local: can only be used in a function.

Quindi la mia un'altra soluzione è quella di racchiudere intero script di configurazione in funzione:

function config_func_rZ0Yqkpm() { 
    local TMP1=abc 
    CONFIG_INPUT_DIR="$TMP1"/in 
    CONFIG_OUTPUT_DIR="$TMP1"/out 
} 
config_func_rZ0Yqkpm 
unset config_func_rZ0Yqkpm 

che è meglio che la soluzione precedente nella manutenibilità e la leggibilità, ma c'è qualche possibilità di entrare in conflitto così come la soluzione 1.

Domanda

Voglio conoscere una soluzione più robusta e intelligente senza alcuna possibilità di conflitto.

Grazie.

risposta

4

Un trucco che ho imparato dall'utilità keychain consiste nell'utilizzare un programma per creare un file di tipo source contenente solo le variabili che si desidera esportare dal programma. Si potrebbe modificare il vostro script per echo le variabili che si desidera impostare e quindi fonte il uscita dal programma:

$ echo $FOO 

$ source <(echo FOO=bar) 
$ echo $FOO 
bar 
$ 

ho usato echo FOO=bar per simulare lo script più grande; il tuo programma è probabilmente più coinvolto. La parte importante è che è necessario modificare il programma per generare le variabili e i valori che si desidera impostare, anziché limitarsi a impostarli. Questo ti consente di decidere quali variabili esporre e quali mantenere private al costo di un altro processo di shell.

+0

'ssh-agent' usa una tecnica simile, con le opzioni' -c' e '-s'. – jjlin

+0

@jjlin: Grazie! Pensavo che 'keychain' non fosse esattamente il posto in cui l'ho visto per primo, ma era il primo posto in cui ho trovato la documentazione. :) Divertente, è seduto proprio lì all'aperto nella manpage di 'ssh-agent' ... – sarnold

+0

@sarnold: Grande, grazie! Proverò questa tecnica. – niboshi

0

I due metodi usuali di creazione di un nome file univoco sono l'uso della funzione mktemp, che è garantita per creare un nome file univoco, o per incorporare il PID nel nome del file. Il PID si troverà nella variabile '$$'.

+0

Il problema non è la costruzione di nomi di file unici ma unico names_ _variable. (O, meglio ancora, un meccanismo di scoping.) – sarnold

+0

Gotcha. ... Sono stato confuso dall'uso di '$ CONFIG_INPUT_DIR' ... sintatticamente, è una variabile, semanticamente, è una directory. –

6

Si potrebbe evitare di variabili e funzioni d'uso in config.sh per tenere i vostri valori:

get_dirname() { echo "abc"; } 
CONFIG_INPUT_DIR="$(get_dirname)/in" 
CONFIG_OUTPUT_DIR="$(get_dirname)/out" 
unset -f get_dirname 

Se siete ancora preoccupati per nome di collisione per le funzioni, questo non aiuta voi.

4

Il metodo "ssh-agent":

config.sh

#!/bin/bash 
TMP=abc 
printf "CONFIG_INPUT_DIR=%s/in" "$TMP" 
printf "CONFIG_OUTPUT_DIR=%s/out" "$TMP" 

programma principale:

TMP1=def 
eval $(config.sh) 
echo $TMP1 
Problemi correlati