2014-07-10 25 views
7

Ho bisogno di una funzione bash per restituire una stringa costruita dinamicamente da restituire allo spazio del chiamante. cioè,Bash: Restituisce una stringa dalla funzione bash

makeName() 
{ 
    echo "Enter Ext: " 
    read ext 
    return "$fileName.$1.$ext.log" 
} 


echo -n "Enter fileName:" 
read fileName 

name1=makeName "type1" 
name2=makfName "type2" 

così posso avere due nomi di file diversi con lo stesso nome del file di base. I tentativi che fanno in questo modo,

# echo $(makeName "type1") 

Ma questo codice è colpito da qualche parte con qualsiasi ragione o errori. Mi aspetto che accetti anche un qualche tipo di I/O con quel proc. Non sta succedendo.

risposta

12

La dichiarazione return utilizzata da bash viene utilizzata per restituire un valore numerico come codice di stato da recuperare tramite $? dalla funzione di chiamata. Non puoi restituire una stringa. Vedi anche

è possibile utilizzare una variabile globale speciale come proposto da @konsolebox, o echo il valore di ritorno all'interno della vostra funzione e utilizzare la sostituzione di comando quando si chiama la funzione :

makeName() 
{ 
    echo "$fileName.$1.log" 
} 


echo -n "Enter fileName:" 
read fileName 

name1=$(makeName "type1") 
name2=$(makeName "type2") 

echo $name1 
echo $name2 

[UPDATE]

La domanda aggiornata mostra che si intende leggere ancora un altro valore all'interno della funzione makeName, mentre la funzione intende anche echo qualche richiesta per l'utente. Quindi l'approccio sostituzione di comando non funziona in questo caso - è necessario utilizzare una variabile globale, come

makeName() { 
    echo -n "Enter Ext: " 
    read ext 

    __="$fileName.$1.$ext.log" 
} 


echo -n "Enter fileName:" 
read fileName 

makeName "type1" ; name1=${__} 
makeName "type2" ; name2=${__} 

echo $name1 
echo $name2 
$ ./sample.sh 
Enter fileName:filename 
Enter Ext: ext1 
Enter Ext: ext2 
filename.type1.ext1.log 
filename.type2.ext2.log 

Eppure meglio, per il codice più pulito e di evitare l'uso di variabili globali all'interno della vostra funzione, potrebbe utilizzare l'approccio descritto in Returning Values from Bash Functions e passare il nome della variabile ritorno come parametro, e idealmente anche passare il fileName come parametro:

makeName() { 
    local __type=$1 
    local __fileName=$2 
    local __resultvar=$3 
    local ext 
    local myresult 

    echo -n "Enter Ext: " 
    read ext 
    myresult="$__fileName.$__type.$ext.log" 

    eval $__resultvar="'$myresult'" 
} 

echo -n "Enter fileName:" 
read fileName 

makeName "type1" $fileName theResult ; name1=${theResult} 
makeName "type2" $fileName theResult ; name2=${theResult} 
echo $myresult 

echo $name1 
echo $name2 

Nota a margine: Vedere Why should eval be avoided in Bash, and what should I use instead? per una discussione sul perché eval deve essere evitato. Quando si utilizza bash versione 3.1 o superiore, è possibile utilizzare printf invece di eval:

... 
printf -v "$__resultvar" '%s' "$myresult" 
... 

E, infine, con bash 4.3 o superiore, siamo in grado di assegnare il nameref attributo ad una variabile utilizzando declare -n, in modo che il variabile è effettivamente un riferimento ad un'altra variabile:

... 
declare -n myresult=$3 

myresult="$__fileName.$__type.$ext.log" 
... 
+0

Ciao Andreas, ho aggiornato la mia domanda. – Ashwin

+1

Vedere la mia risposta aggiornata - in sostanza, hai abusato di 'return', e devi anche usare l'approccio proposto da @konsolebox quando la tua funzione intende stampare l'output su stdout (diverso dal valore restituito) –

+0

Grazie Andreas. Funziona bene ora. :) – Ashwin

4

modo migliore è quello di scegliere una variabile generale si può sempre usare.Esempio:

makeName() { 
    __="$fileName.$1.log" 
}  

echo -n "Enter fileName:" 
read fileName 

makeName "type1" 
name1=$__ 
makeName "type2" 
name2=$__ 

echo "$name1" 
echo "$name2" 

L'evocazione di sottochiavi solo per ottenere un valore da una funzione è davvero inefficiente e lenta.

+0

+1 buon punto nella sub shell - Probabilmente preferirei ancora sub shell su variabili globali ;-), ma il tuo approccio è decisamente più veloce (il ciclo delle due chiamate 'makeName' 1000 volte richiede meno di 100ms, mentre la sub shell soluzione basata richiede quasi 2 secondi). –

+0

natura criptica di bash non smette mai di stupirmi :-) – raffian

0

Basta sostituire return con echo:

makeName() 
{ 
    echo "Enter Ext: " >&2 
    read ext 
    echo "$fileName.$1.$ext.log" 
} 
+1

Che finirà con 'Enter Ext:' che fa parte del risultato ... –

+0

Oops. Il prompt dovrebbe invece essere stampato con errore standard, con 'echo" Enter Ext: "> & 2', o usando l'opzione' -p' disponibile per l'implementazione di 'read' di bash' per visualizzare invece il prompt ('read -p" Enter Ext: "ext'). – chepner

+0

... e, è ancora necessario utilizzare la sostituzione di comando quando si chiama 'makeName' (quale OP non funziona correttamente e quale porta alla discussione che abbiamo appena avuto con @konsolebox ;-)) –