Le variabili che ottengono ripristino dopo il tempo di leggere ciclo che legge da un oleodotto
-
26-10-2019 - |
Domanda
initiate () {
read -p "Location(s) to look for .bsp files in? " loc
find $loc -name "*.bsp" | while read
do
if [ -f "$loc.bz2" ]
then
continue
else
filcount=$[$filcount+1]
bzip $loc
fi
if [ "$scan" == "1" ]; then bzipint $loc
fi
echo $filcount #Correct counting
echo $zipcount #Correct counting
echo $scacount #Correct counting
echo $valid #Equal to 1
done
echo $filcount #Reset to 0
echo $zipcount #Reset to 0
echo $scacount #Reset to 0
echo $valid #Still equal to 1
}
Sto scrivendo uno script di shell bash per usare bzip2
per comprimere tutti i file .bsp
all'interno di una directory. In questo script ho diverse variabili per i totali di conteggio (file, cerniere di successo, scansioni di integrità di successo), ma mi sembra di aver incontrato un problema.
Quando find $loc -name "*.bsp"
esaurisce file per dare le uscite while read
e while read
, azzera fuori $filcount
, $zipcount
e $scacount
(che sono tutti modificato (aumentato) all'interno initiate ()
, bzip ()
(che si chiama durante initiate ()
) o bzipint ()
(che è chiamato anche in initiate ()
).
Per prova se esso è a che fare con le variabili cambiando initiate ()
all'interno o altre funzioni accessibili da esso, ho usato eco $valid
, che è definita al di fuori di initiate ()
(come $filcount
, $zipcount
, ecc), ma non è cambiato da un'altra initiate ()
funzione all'interno o initiate ()
suo interno.
È interessante notare che, $valid
non viene reimpostato a 0, come le altre variabili all'interno avviare.
Qualcuno può dirmi il motivo per cui le mie variabili magicamente diventano resettato quando, mentre leggere uscite?
Soluzione
mi sono imbattuto in questo problema ieri.
Il problema è che si sta facendo find $loc -name "*.bsp" | while read
. Poiché si tratta di un tubo, il ciclo while read
non può di fatto essere in esecuzione nello stesso processo bash come il resto dello script; bash deve generare un sottoprocesso modo che possa collegare lo stdout di find
al stdin del ciclo while
.
Questo è tutto molto intelligente, ma significa che tutte le variabili impostate nel ciclo non può essere visto dopo il ciclo, che totalmente sconfitto l'intero scopo del ciclo while
che stavo scrivendo.
Puoi provare ad alimentare input per il ciclo senza l'utilizzo di un tubo, o ottenere l'uscita dal loop senza l'utilizzo di variabili. Ho finito con un abominio terrificante che coinvolge sia la scrittura di un file temporaneo e avvolgendo l'intero ciclo in $(...)
, in questo modo:
var="$(producer | while read line; do
...
echo "${something}"
done)"
Il che mi ha fatto var insieme a tutte le cose che erano state eco dal loop. Probabilmente ho incasinato la sintassi di questo esempio; Non ho il codice che ho scritto a portata di mano in questo momento.
Altri suggerimenti
se si utilizza bash
while read
do
if [ -f "$REPLY.bz2" ]
then
continue
else
filcount=$[$filcount+1]
bzip $REPLY
fi
if [ "$scan" == "1" ]; then bzipint $REPLY
fi
echo $filcount #Correct counting
echo $zipcount #Correct counting
echo $scacount #Correct counting
echo $valid #Equal to 1
done < <(find $loc -name "*.bsp")
Per le opzioni Riassumere per utilizzando read
alla fine del [l'equivalente concettuale di] una pipeline in POSIX-come gusci:
Per ricapitolare: in bash di default e conchiglie rigorosamente POSIX-compliant sempre, tutti i comandi in una corsa condotta in un subshell , quindi variabili creano o di modifica non saranno visibili al corrente shell (non esisterà dopo la fine della pipeline).
Il seguente copertine bash
, ksh
, zsh
, e sh
([principalmente] POSIX-caratteristiche di sola gusci come dash
) e spettacoli modi per evitare la creazione di una subshell così come per preservare le variabili creato / modificato con read
.
Se non viene dato alcun numero di versione minima, supporre che anche "abbastanza vecchie" versioni supportano (le caratteristiche in questione sono stati in giro per molto tempo, ma non so precisamente quando sono stati introdotti.
Si noti che come alternativa [POSIX-compliant] per le soluzioni di seguito si può sempre catturare l'output di un comando in un file [temporanea], e poi alimentarlo a read
come < file
, che evita anche sottoshell.
ksh
, e zsh
: nessuna soluzione modifica / configurazione necessaria a tutti:
Il comando incorporato read
di default viene eseguito in corrente shell quando utilizzato come ultima di comando nella pipeline.
Apparentemente, ksh
e zsh
di default Esegui qualsiasi comando nella ultima tappa di un oleodotto nella corrente shell .
Osservato in ksh 93u+
e zsh 5.0.5
.
Se si conosce in particolare in che versione questa funzionalità è stata introdotta, fatemelo sapere.
#!/usr/bin/env ksh
#!/usr/bin/env zsh
out= # initialize output variable
# Pipe multiple lines to the `while` loop and collect the values in the output variable.
printf '%s\n' one two three |
while read -r var; do
out+="$var/"
done
echo "$out" # -> 'one/two/three/'
bash 4.2+
: utilizzare l'opzione di shell lastpipe
Nella versione bash 4.2 o superiore, attivando l'opzione di shell lastpipe
fa sì che l'ultimo segmento di conduttura per l'esecuzione in corrente conchiglia, permettendo di leggere per creare le variabili visibili alla shell corrente.
#!/usr/bin/env bash
shopt -s lastpipe # bash 4.2+: make the last pipeline command run in *current* shell
out=
printf '%s\n' one two three |
while read -r var; do
out+="$var/"
done
echo "$out" # -> 'one/two/three/'
bash
, ksh
, zsh
: uso sostituzione
In parole povere, una sostituzione di processo è un modo per avere atto output di un comando come un file temporaneo.
out=
while read -r var; do
out+="$var/"
done < <(printf '%s\n' one two three) # <(...) is the process substitution
echo "$out" # -> 'one/two/three'
bash
, ksh
, zsh
: utilizzare un stringa here con un < a href = "http://mywiki.wooledge.org/CommandSubstitution" rel = "noreferrer"> comando cambio
out=
while read -r var; do
out+="$var/"
done <<< "$(printf '%s\n' one two three)" # <<< is the here-string operator
echo "$out" # -> 'one/two/three'
Si noti la necessità di raddoppiare-citare la sostituzione di comando per proteggere la sua uscita da espansioni della shell .
POSIX-compliant soluzione (sh
): utilizzare un qui-documento con un la sostituzione di comando
#!/bin/sh
out=
while read -r var; do
out="$out$var/"
done <<EOF # <<EOF ... EOF is the here-doc
$(printf '%s\n' one two three)
EOF
echo "$out" # -> 'one/two/three'
Si noti che, per impostazione predefinita, è necessario inserire il delimitatore finale - EOF
, in questo caso -. Proprio all'inizio della linea, e che non personaggi devono seguirla