2012-08-10 10 views
11

Ich suche nach einer Implementierung eines ‚cacheme‘ Befehl, die ‚memoizes‘ die Ausgabe von was auch immer in ARGV hat. Wenn es nie ausgeführt wird, wird es es laufen lassen und die Ausgabe etwas merken. Wenn es ausgeführt wird, kopiert es nur die Ausgabe der Datei (oder noch besser, beide Ausgabe und Fehler zu & 1 bzw. & 2).Kann ich die Ausgabe eines Befehls unter Linux von CLI zwischenspeichern?

Nehmen wir an, jemand schrieb diesen Befehl, es würde so funktionieren.

$ 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 

Dieses Beispiel ist ein bisschen dumm, weil es keine Ausgabe hat. Im Idealfall würde es auf einem Skript wie sleep-1-and-echo-hello-world.sh getestet werden.

Ich habe ein kleines Skript erstellt, das eine Datei in/tmp/mit Hash von vollem Befehlsnamen und Benutzernamen erstellt, aber ich bin mir ziemlich sicher, dass etwas bereits existiert.

Ist Ihnen das bekannt?

+0

Was ist der Anwendungsfall? Warum würdest du das wollen? –

+1

Zum Beispiel, ein Skript, das Ewigkeiten zur Ausführung benötigt, aber normalerweise eine konsistente Ausgabe liefert, in Fällen, in denen Sie nicht daran interessiert sind, eine neue Antwort zu haben, sondern nur eine gute, nicht zu alte Version. – Riccardo

+1

Dies ist sehr nah dran, was 'make' macht –

Antwort

1

Verbesserte Lösung oben etwas durch Hinzufügen von Ablaufdatum als optionales Argument.

#!/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. Vielleicht wäre eine Verwendung schön: "yourscript.sh Schlaf 1" funktioniert nicht. 2.Ich verstehe Zeile 6 nicht: Was ist ["$ 1" -eq "$ 1"] für? – Riccardo

+0

Einige Kommentare zur Dokumentation hinzugefügt. Das "$ 1" -eq "$ 1" -Stück ist magisch, um zu erkennen, ob das erste Argument für eine Ganzzahl - wenn ja - es verwendet, um die Ablaufzeit in Sekunden zu setzen. Außerdem wurde eval hinzugefügt, damit es mit Argumenten wie in "yourscript.sh sleep 1" funktioniert. – error

+2

Dieses Ding ist großartig, hat jemand ein richtiges Util davon gemacht? Gewünschte Features, Dokumente, Speicherbereinigung (derzeit werden die abgelaufenen Cache-Elemente nur gelöscht, wenn sie überschrieben werden), verschiedene Flags, (nur Cache verwenden, stderr zwischenspeichern, Exit-Codes zwischenspeichern) und einige POSIX-Skriptoptimierungen. – agc

1

Die Lösung, die ich in Rubin kam, ist dies. Sieht jemand eine Optimierung?

#!/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

Wie wäre es mit diesem einfachen Shell-Skript (nicht getestet)?

+0

es funktioniert nicht :( Cache: Zeile 13: unerwartete EOF bei der Suche nach passenden '' ' Cache: Zeile 14: Syntaxfehler: unerwartetes Ende der Datei – Riccardo

+1

Korrigiert den offensichtlichen Fehler (Schließen '"' in Zeile 12) Arbeit jetzt –

1

Ich habe ein einfaches Caching-Skript für bash implementiert, weil ich speed up plotting from piped shell command in gnuplot wollte. Es kann verwendet werden, um die Ausgabe eines beliebigen Befehls zwischenzuspeichern. Cache wird verwendet, solange die Argumente identisch sind und Dateien, die in Argumenten übergeben werden, nicht geändert wurden. System ist verantwortlich für die Reinigung.

#!/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 

können Sie nennen das Skript cache, ausführbar Flag und setzen Sie es in Ihrem PATH. Fügen Sie dann einfach einen beliebigen Befehl mit cache voran, um ihn zu verwenden.

0

Eine Implementierung existiert hier: https://bitbucket.org/sivann/runcached/src Caches ausführbaren Pfad, Ausgabe, Exit-Code, merkt sich Argumente. Konfigurierbarer Ablauf Implementiert in Bash, C, Python, wählen Sie, was Ihnen passt.

Verwandte Themen