2012-08-10 22 views
11

Estoy buscando una implementación de un comando 'cacheme', que 'memoizes' la salida de lo que tenga en ARGV. Si nunca lo ejecutó, lo ejecutará y memorizará la salida. Si se ejecutó, simplemente copiará la salida del archivo (o incluso mejor, tanto la salida como el error a & 1 y & 2 respectivamente).¿Puedo almacenar en caché el resultado de un comando en Linux desde CLI?

Supongamos que alguien escribió este comando, funcionaría así.

$ time cacheme sleep 1 # first time it takes one sec 
real 0m1.228s 
user 0m0.140s 
sys 0m0.040s 

$ time cacheme sleep 1 # second time it looks for stdout in the cache (dflt expires in 1h) 
#DEBUG# Cache version found! (1 minute old) 

real 0m0.100s 
user 0m0.100s 
sys 0m0.040s 

Este ejemplo es un poco tonto porque no tiene salida. Idealmente se probaría en un script como sleep-1-and-echo-hello-world.sh.

Creé un pequeño script que crea un archivo en/tmp/con hash del nombre completo del comando y nombre de usuario, pero estoy bastante seguro de que algo ya existe.

¿Conoces algo de esto?

+0

¿Cuál es el caso de uso? Por qué querrías esto ? –

+1

Por ejemplo, una secuencia de comandos que tarda años en ejecutarse, pero normalmente ofrece resultados consistentes, en los casos en los que no está interesado en tener una respuesta nueva, sino simplemente una buena versión no demasiado vieja. – Riccardo

+1

Esto está muy cerca de lo que 'make' hace –

Respuesta

1

Solución mejorada anteriormente añadiendo un límite de caducidad como argumento opcional.

#!/bin/sh 
# save as e.g. $HOME/.local/bin/cacheme 
# and then chmod u+x $HOME/.local/bin/cacheme 
VERBOSE=false 
PROG="$(basename $0)" 
DIR="${HOME}/.cache/${PROG}" 
mkdir -p "${DIR}" 
EXPIRY=600 # default to 10 minutes 
# check if first argument is a number, if so use it as expiration (seconds) 
[ "$1" -eq "$1" ] 2>/dev/null && EXPIRY=$1 && shift 
[ "$VERBOSE" = true ] && echo "Using expiration $EXPIRY seconds" 
CMD="[email protected]" 
HASH=$(echo "$CMD" | md5sum | awk '{print $1}') 
CACHE="$DIR/$HASH" 
test -f "${CACHE}" && [ $(expr $(date +%s) - $(date -r "$CACHE" +%s)) -le $EXPIRY ] || eval "$CMD" > "${CACHE}" 
cat "${CACHE}" 
+0

1. Tal vez un uso sería bueno: "yourscript.sh sleep 1" no funciona. 2.No entiendo la línea 6: ¿para qué es ["$ 1" -eq "$ 1"]? – Riccardo

+0

Se agregaron algunos comentarios para la documentación. el elemento "$ 1" -eq "$ 1" es mágico para detectar si el primer argumento es un entero; de ser así, úselo para establecer el tiempo de expiración en segundos. También se agregó eval para que funcione con argumentos como en "yourscript.sh sleep 1". – error

+2

Esto es genial, ¿alguien ha hecho un uso adecuado de él? Funciones deseadas, documentos, recolección de basura (actualmente los elementos de caché caducados solo se eliminan cuando se sobrescriben), varios indicadores (solo usan caché, almacenamiento en caché, códigos de salida de caché) y algunas optimizaciones de script POSIX. – agc

1

La solución que encontré en ruby ​​es esta. ¿Alguien ve alguna optimización?

#!/usr/bin/env ruby 

VER = '1.2' 
$time_cache_secs = 3600 
$cache_dir = File.expand_path("~/.cacheme") 

require 'rubygems' 
begin 
    require 'filecache'   # gem install ruby-cache 
rescue Exception => e 
    puts 'gem filecache requires installation, sorry. trying to install myself' 
    system 'sudo gem install -r filecache' 
    puts 'Try re-running the program now.' 
    exit 1 
end 

=begin 
    # create a new cache called "my-cache", rooted in /home/simon/caches 
    # with an expiry time of 30 seconds, and a file hierarchy three 
    # directories deep 
=end 
def main 
    cache = FileCache.new("cache3", $cache_dir, $time_cache_secs, 3) 
    cmd = ARGV.join(' ').to_s # caching on full command, note that quotes are stripped 
    cmd = 'echo give me an argment' if cmd.length < 1 

    # caches the command and retrieves it 
    if cache.get('output' + cmd) 
    #deb "Cache found!(for '#{cmd}')" 
    else 
    #deb "Cache not found! Recalculating and setting for the future" 
    cache.set('output' + cmd, `#{cmd}`) 
    end 
    #deb 'anyway calling the cache now' 
    print(cache.get('output' + cmd)) 
end 

main 
2

¿Qué le parece este sencillo script de shell (no probado)?

#!/bin/sh 

mkdir -p cache 

cachefile=cache/cache 

for i in "[email protected]" 
do 
    cachefile=${cachefile}_$(printf %s "$i" | sed 's/./\\&/g') 
done 

test -f "$cachefile" || "[email protected]" > "$cachefile" 
cat "$cachefile" 
+0

no funciona :( caché: línea 13: EOF inesperado mientras buscaba coincidencia '" ' caché: línea 14: error de sintaxis: inesperado final del archivo – Riccardo

+1

Corregido el error obvio (cerrando '"' en la línea 12). trabaje ahora. –

1

he implementado un script sencillo para el almacenamiento en caché fiesta, porque quería speed up plotting from piped shell command in gnuplot. Se puede usar para almacenar en caché la salida de cualquier comando. La memoria caché se utiliza siempre que los argumentos sean los mismos y los archivos que pasen en argumentos no hayan cambiado. El sistema es responsable de la limpieza.

#!/bin/bash 

# hash all arguments 
KEY="[email protected]" 

# hash last modified dates of any files 
for arg in "[email protected]" 
do 
    if [ -f $arg ] 
    then 
    KEY+=`date -r "$arg" +\ %s` 
    fi 
done 

# use the hash as a name for temporary file 
FILE="/tmp/command_cache.`echo -n "$KEY" | md5sum | cut -c -10`" 

# use cached file or execute the command and cache it 
if [ -f $FILE ] 
then 
    cat $FILE 
else 
    [email protected] | tee $FILE 
fi 

Usted puede nombrar el guión cache, establecer el indicador ejecutable y lo puso en su PATH. Luego simplemente prefija cualquier comando con cache para usarlo.

0

Existe una implementación aquí: https://bitbucket.org/sivann/runcached/src Caché de ruta ejecutable, salida, código de salida, recuerda argumentos. Expiración configurable Implementado en bash, C, python, elige lo que más te convenga.

Cuestiones relacionadas