2014-07-22 15 views
9

Scrivo uno script in cui è necessario utilizzare l'output di un file test in più posizioni, incluso all'interno di una funzione shell. Vorrei assegnare il file esistenza a una variabile di shell, come questo: file_exists=[ -f $myfile ].Assegnazione del risultato di "test" a una variabile

Giusto per fare in modo che ho i miei basi coperte, comincio toccando un file, e testare la sua esistenza:

file='a' 
touch $file 
if [ -f $file ] 
then 
    echo "1 -- '$file' exists" 
fi 

uscita:

1 -- 'a' exists 

Il file è stato creato con successo - Nessuna sorpresa, ma almeno so che non ho a che fare con problemi di permessi o altro.

Avanti I test per assicurarsi che io possa memorizzare un'espressione booleana in una variabile:

mytest=/bin/true 

if $mytest 
then 
    echo "2 -- \$mytest is true" 
fi 

uscita:

2 -- $mytest is true 

Così ho gli elementi fondamentali - espressioni condizionali dovrebbe emettono lo stesso output /bin/true o /bin/false ... ma non è quello che sto vedendo:

mytest=[ -f $file ] 
if $mytest 
then 
    echo "3 -- \$mytest is true [expect true]" 
else 
    echo "3 -- \$mytest is false [expect true]" 
fi 

Questo non riesce con il seguente errore:

-f: command not found 

ottengo lo stesso messaggio di errore se io uso test -f $file piuttosto che [ -f $file ].

Se metto uno spazio davanti alla [, l'errore va via ...

mytest= [ -f $file ] 
if $mytest 
then 
    echo "4 -- \$mytest is true [expect true]" 
else 
    echo "4 -- \$mytest is false [expect true]" 
fi 

L'uscita sembra essere corretta:

4 -- $mytest is true [expect true] 

... ma se rimuovo il file, che dovrebbe ottenere il risultato opposto:

rm $file 
mytest= [ -f $file ] 
if $mytest 
then 
    echo "5 -- \$mytest is true [expect false]" 
else 
    echo "5 -- \$mytest is false [expect false]" 
fi 

... e non fare:

012.
5 -- $mytest is true [expect false] 

Per essere onesti, mi aspettavo lo spazio di pasticciare con il valore di verità:

mytest= /bin/false 
if $mytest 
then 
    echo "6 -- \$mytest is true [expect false]" 
else 
    echo "6 -- \$mytest is false [expect false]" 
fi 

Uscite:

6 -- $mytest is true [expect false] 

Allora, come faccio a memorizzare l'uscita dal test incorporato in una variabile di shell?

+0

'mytest =/bin/true' questo sta memorizzando la stringa ** **'/bin/true 'nella variabile' $ mytest'. –

risposta

21

Come altri hanno documentato qui, l'utilizzo della stringa "true" è un'aringa rossa; questo è non un modo appropriato per memorizzare i valori booleani negli script di shell, in quanto valutarlo significa richiamare dinamicamente un comando piuttosto che semplicemente ispezionare il valore memorizzato utilizzando i builtin di shell codificati nel proprio script.

Invece, se proprio deve conservare uno stato di uscita, farlo come un valore numerico:

[ -f "$file" ]    # run the test 
result=$?     # store the result 

if ((result == 0)); then # 0 is success 
    echo "success" 
else       # nonzero is failure 
    echo "failure" 
fi 
3

mytest=/bin/true sta memorizzando la stringa/bin/true nella variabile $mytest.

mytest=[ -f $file ] è l'impostazione della variabile $mytest al valore [ per la durata del comando -f $file ] (che come output indica riesce perché non c'è -f comando disponibile).

mytest= [ -f $file ] (come sopra) imposta il valore della variabile $mytest a vuoto per tutta la durata del comando [ -f $file ] (e restituisce qualunque [ ritorni).

mytest= /bin/false questo è lo stesso del caso precedente, solo il comando da eseguire è /bin/false.

Se si desidera memorizzare il codice di ritorno da un comando in una variabile si può fare

/bin/true 
ret=$? 

se si desidera memorizzare l'output di un comando in una variabile si può fare

out=$(/bin/true) 

(sebbene con /bin/true tale variabile sia vuota in quanto non emette alcun testo

Per il tuo caso vuoi il precedente modello $?.

Inoltre, l'utilizzo di set -x (e/o set -v) negli script potrebbe averlo aiutato a diagnosticare ciò.

+0

in realtà, questo arriva al dolore un po 'più tardi ... quando immagazzino il valore di '$?', Non posso riesaminarlo più tardi - 'testme = $ ?; se $ testme; quindi echo "ts-da"; altrimenti echo "bzzzt"; fi' restituisce '-bash: 0: comando non trovato', perché l'istruzione' if' sta cercando di eseguire il suo argomento come comando e valuta il successo di quel comando. –

+1

Corretto, non si esegue la variabile. Tu controlli il suo valore. È '0' o qualcos'altro.'if [" $ testme "-eq 0]; quindi' –

6

È necessario citare gli spazi bianchi:

mytest='[ -f $file ]' 
if $mytest; then echo yes; fi 

Tuttavia, questo è estremamente fragile e potenzialmente insicura. Vedi http://mywiki.wooledge.org/BashFAQ/050 per una discussione dettagliata e alcuni modi migliori per realizzare qualcosa di simile.

Se si vuole incapsulare un pezzo complesso di codice, una funzione di solito è la strada da percorrere:

mytest() { [ -f "$file" ]; } 
if mytest; then echo yes; fi 

Se si desidera eseguire il codice una volta e memorizzare il risultato in modo da poter esaminare in un secondo momento, Lo riformerei in questo modo:

if [ -f "$file" ]; then 
    mytest=true 
else 
    mytest=false 
fi 
if $mytest; then echo yes; fi 
+0

Sono diviso qui; Il riferimento BashFAQ # 50 è sempre degno di menzione, ma mostrare 'mytest = [-f $ file]' senza mostrare una pratica migliore a fianco è probabilmente incoraggiante il pigro ad usarlo nonostante l'avvertimento. –

+0

Dovrei essere d'accordo, ma non riesco davvero a indovinare ciò che l'OP vuole davvero. – tripleee

+0

Non sono sicuro che sia necessario indovinare; Riesci a pensare a un caso d'uso (* qualsiasi * caso d'uso) in cui il campione rappresenta una pratica appropriata come attualmente fornita? –

Problemi correlati