2012-09-08 22 views
10

He hecho un script bash que ejecuto cada hora con crontab, y necesito almacenar una variable para poder acceder a ella la próxima vez que la ejecute. La secuencia de comandos cambia la variable cada vez que se ejecuta, por lo que no puedo codificarla. En este momento, la escribo en un archivo txt y luego la leo nuevamente. ¿Hay una mejor manera de hacerlo que esto? Y la forma en que estoy leyendo el archivo txt es algo que encontré aquí, no lo entiendo, y es un poco torpe. ¿No hay un comando incorporado para esto? De todos modos, aquí está el código aplicable, con algunas de las variables modificadas para que sea más fácil de leer.bash: ¿mejor forma de almacenar variables entre ejecuciones?

while read x; do 
    var=$x 
done < var.txt 

# Do some stuff, change var to a new value 

echo $var > var.txt 

La variable es solo un entero, por lo que el archivo de texto se siente excesivo.

+1

El archivo de texto corto que contiene datos persistentes es exactamente la manera de hacerlo, nada raro. – user4815162342

Respuesta

6

No es necesario utilizar var; x estará en el alcance para el shell actual. Alternativamente,

read var < var.txt 
# do stuff with var 
echo $var > var.txt 

recomiendo el uso de un archivo de texto simple para almacenar la variable. Sin embargo, existe la opción (altamente cuestionable) de una secuencia de comandos auto modificante. ¡CON FINES DE ENTRETENIMIENTO SOLAMENTE!

#!/bin/bash 

read val < <(tail -n 1 "$0") 

((val++)) 
echo "$val" 

tmp=$(mktemp /tmp/XXXXXXX) 
sed '$s/.*/'$val'/' "$0" > "$tmp" 
mv "$tmp" "$0" 

exit 
0 

La clave es tener la línea siguiente a la última sea la orden de salida, por lo que nada después de que se ejecutará. La última línea es el valor de la variable que desea persistir. Cuando se ejecuta el script, es read s desde su última línea. Antes de que finalice, usa sed para escribir una copia de sí mismo en un archivo temporal, con la última línea modificada con el valor actual del valor persistente. Luego sobrescribimos la secuencia de comandos actual con el archivo temporal (suponiendo que tengamos permiso para hacerlo).

¿Pero en serio? No hagas esto

+0

Gracias, eso es mucho más simple. ¿Son los archivos de texto la mejor manera de hacer esto? – shardbearer

+0

@shardbearer: Depende. Puede elegir entre archivos, bases de datos, otros almacenes de persistencia de objetos java/ruby ​​/ python más exóticos, o mantener su programa ejecutándose en un ciclo infinito (con tiempos de inactividad adecuados incrustados) y almacenar el valor en memoria, dependiendo de cuáles sean sus requisitos generales son. La persistencia de archivos suele ser lo suficientemente buena. Si te estás metiendo en un sistema mongo con miles de archivos y directorios (como se ha postulado recientemente aquí en S.O.), entonces necesitarás dedicar algo de tiempo a encontrar la tecnología adecuada. Buena suerte a todos. – shellter

+0

Downvoter: por favor comente sobre su razón. ¿Es por el abominable código de auto modificación? :) – chepner

1

1- Puede simplificar su escritura, ya que sólo tiene una variable

var=`cat var.txt` 
# Do some stuff, change var to a new value 
echo $var > var.txt 

2- Puede almacenar su variable en el entorno:

export var 

# Do some stuff, change var to a new value 

pero necesitará para solicitar es . script.ksh (dot at the beggining). Pero no debería tener 'exit' en él y no estoy seguro de que esto funcione en cron ...

-1

Terminé haciendo lo siguiente. Preferiría las variables en un archivo, pero esto hincha el código ligeramente. ¿Cómo funciona esto leído? Puede almacenar múltiples variables en un archivo separado, digamos variables.txt, y luego tener su programa principal en main.sh. Sin embargo, podría ser mejor escribir scripts separados para cargar y guardar variables.

Para varibles.txt:

A=0 
B=0 
C=0 

Para main.sh:

#!/bin/bash 

#reload variables 
A=`cat ./variables.txt|grep "A="|cut -d"=" -f2` 
B=`cat ./variables.txt|grep "B="|cut -d"=" -f2` 
C=`cat ./variables.txt|grep "C="|cut -d"=" -f2` 

#print variables 
printf "$A\n" 
printf "$B\n" 
printf "$C\n" 

#update variables 
A=$((($A+1))) 
B=$((($B+2))) 
C=$((($C+3))) 

#save variables to file 
#for A 
#remove entry for A 
cat ./variables.txt|grep -v "A=">>./tmp.txt 
#save entry for A 
printf "A=$A\n">>./tmp.txt 
#move tmp.txt to variables.txt 
mv ./tmp.txt ./variables.txt 

#for B 
#remove entry for B 
cat ./variables.txt|grep -v "B=">>./tmp.txt 
#save entry for B 
printf "B=$B\n">>./tmp.txt 
#move tmp.txt to variables.txt 
mv ./tmp.txt ./variables.txt 

#for C 
#remove entry for C 
cat ./variables.txt|grep -v "C=">>./tmp.txt 
#save entry for C 
printf "C=$C\n">>./tmp.txt 
#move tmp.txt to variables.txt 
mv ./tmp.txt ./variables.txt 
+2

Sin ofender, pero esto es terrible. Será mejor que 'fuente' el archivo' variables.txt' en lugar de analizarlo usted mismo. ¡Además, los usos inútiles del gato manchados! –

2

Sé que esto es una cuestión de edad. Pero, aún así, decido publicar mi solución aquí con la esperanza de que pueda ser útil para otros que vienen aquí en busca de una forma de serializar archivos entre sesiones.

La manera simple es simplemente escribir "var_name = var_value" en un archivo, digamos "./environ". Y luego "fuente ./envrion" en las siguientes sesiones.Por ejemplo:

echo "var1=$var1" > ./environ 

Una forma más completa (? Y elegante) que persisten todos los atributos de las variables es hacer uso de "declarar -p":

declare -p var1 var2 > ./environ 
# NOTE: no '$' before var1, var2 

Más tarde, después de "fuente./envrion "puede obtener var1 var2 con todos los atributos restaurados además de su valor. Esto significa que puede manejar matrices, enteros, etc.

Sin embargo, una advertencia para el "declare -p xx": si ajusta el "origen/servidor" en una función, entonces todas las variables de origen son visibles dentro de la función solo porque "declarar" de forma predeterminada declara las variables como locales. Para evitar esto, puede "fuente" de cualquier función (o en su función "principal") o modificar ./environ para agregar "-g" después de declarar (lo que hace que la variable correspondiente sea global). Por ejemplo:

sed -i 's/^declare\(-g\)*/declare -g/' ./environ 
# "\(-g\)?" ensure no duplication of "-g" 
+0

Este es un enfoque simple, y lo uso yo mismo. Exige cuidado, si los usuarios no confiables pueden escribir en el archivo (por ejemplo, si está en '/ tmp' y no se creó inicialmente), ya que contiene todas las capacidades del shell de origen. ¡Cuídate! –

+0

@TobySpeight tienes razón, y gracias. –

Cuestiones relacionadas